From 68ce366958e7778c7f088bd950cfd965e3791e95 Mon Sep 17 00:00:00 2001 From: Drullkus Date: Sun, 17 Dec 2023 00:08:53 -0800 Subject: [PATCH] Fuse a bunch of WorldEdit development modules into 1, NeoForged port --- build.gradle | 79 + gradle.properties | 14 +- .../com/sk89q/worldedit/antlr/Expression.g4 | 237 ++ .../java/com/example/examplemod/Config.java | 63 - .../com/example/examplemod/ExampleMod.java | 129 - .../java/com/sk89q/jnbt/ByteArrayTag.java | 59 + src/main/java/com/sk89q/jnbt/ByteTag.java | 49 + src/main/java/com/sk89q/jnbt/CompoundTag.java | 438 +++ .../com/sk89q/jnbt/CompoundTagBuilder.java | 228 ++ src/main/java/com/sk89q/jnbt/DoubleTag.java | 49 + src/main/java/com/sk89q/jnbt/EndTag.java | 37 + src/main/java/com/sk89q/jnbt/FloatTag.java | 49 + src/main/java/com/sk89q/jnbt/IntArrayTag.java | 62 + src/main/java/com/sk89q/jnbt/IntTag.java | 49 + src/main/java/com/sk89q/jnbt/ListTag.java | 429 +++ .../java/com/sk89q/jnbt/ListTagBuilder.java | 119 + .../java/com/sk89q/jnbt/LongArrayTag.java | 62 + src/main/java/com/sk89q/jnbt/LongTag.java | 49 + .../java/com/sk89q/jnbt/NBTConstants.java | 92 + .../java/com/sk89q/jnbt/NBTInputStream.java | 179 ++ .../java/com/sk89q/jnbt/NBTOutputStream.java | 307 ++ src/main/java/com/sk89q/jnbt/NBTUtils.java | 195 ++ src/main/java/com/sk89q/jnbt/NamedTag.java | 63 + src/main/java/com/sk89q/jnbt/ShortTag.java | 49 + src/main/java/com/sk89q/jnbt/StringTag.java | 52 + src/main/java/com/sk89q/jnbt/Tag.java | 34 + .../minecraft/util/commands/Command.java | 93 + .../minecraft/util/commands/CommandAlias.java | 40 + .../util/commands/CommandContext.java | 362 +++ .../util/commands/CommandException.java | 84 + .../util/commands/CommandLocals.java | 50 + .../util/commands/CommandPermissions.java | 39 + .../commands/CommandPermissionsException.java | 27 + .../util/commands/CommandUsageException.java | 34 + .../util/commands/CommandsManager.java | 586 ++++ .../minecraft/util/commands/Console.java | 31 + .../minecraft/util/commands/Injector.java | 40 + .../MissingNestedCommandException.java | 28 + .../util/commands/NestedCommand.java | 50 + .../util/commands/SimpleInjector.java | 53 + .../util/commands/SuggestionContext.java | 68 + .../commands/UnhandledCommandException.java | 24 + .../commands/WrappedCommandException.java | 28 + .../minecraft/util/commands/package-info.java | 25 + .../java/com/sk89q/util/ReflectionUtil.java | 43 + src/main/java/com/sk89q/util/StringUtil.java | 334 ++ .../java/com/sk89q/util/yaml/YAMLFormat.java | 37 + .../java/com/sk89q/util/yaml/YAMLNode.java | 846 +++++ .../com/sk89q/util/yaml/YAMLProcessor.java | 318 ++ .../util/yaml/YAMLProcessorException.java | 35 + .../worldedit/DisallowedItemException.java | 47 + .../java/com/sk89q/worldedit/EditSession.java | 2666 ++++++++++++++++ .../sk89q/worldedit/EditSessionBuilder.java | 145 + .../sk89q/worldedit/EditSessionFactory.java | 176 ++ .../worldedit/EmptyClipboardException.java | 27 + .../worldedit/IncompleteRegionException.java | 27 + .../sk89q/worldedit/InvalidItemException.java | 32 + .../sk89q/worldedit/LocalConfiguration.java | 240 ++ .../com/sk89q/worldedit/LocalSession.java | 1208 +++++++ .../worldedit/MaxBrushRadiusException.java | 27 + .../worldedit/MaxChangedBlocksException.java | 48 + .../sk89q/worldedit/MaxRadiusException.java | 28 + .../worldedit/MissingWorldException.java | 32 + .../sk89q/worldedit/NotABlockException.java | 66 + .../sk89q/worldedit/TracedEditSession.java | 52 + .../worldedit/UnknownDirectionException.java | 51 + .../sk89q/worldedit/UnknownItemException.java | 48 + .../java/com/sk89q/worldedit/WorldEdit.java | 848 +++++ .../sk89q/worldedit/WorldEditException.java | 111 + .../sk89q/worldedit/WorldEditManifest.java | 108 + .../com/sk89q/worldedit/blocks/BaseItem.java | 97 + .../sk89q/worldedit/blocks/BaseItemStack.java | 91 + .../com/sk89q/worldedit/blocks/Blocks.java | 83 + .../worldedit/blocks/MobSpawnerBlock.java | 231 ++ .../com/sk89q/worldedit/blocks/SignBlock.java | 169 + .../sk89q/worldedit/blocks/SkullBlock.java | 122 + .../worldedit/blocks/TileEntityBlock.java | 39 + .../worldedit/command/ApplyBrushCommands.java | 143 + .../worldedit/command/BiomeCommands.java | 205 ++ .../worldedit/command/BrushCommands.java | 534 ++++ .../worldedit/command/ChunkCommands.java | 204 ++ .../worldedit/command/ClipboardCommands.java | 264 ++ .../worldedit/command/ExpandCommands.java | 158 + .../command/FlattenedClipboardTransform.java | 136 + .../worldedit/command/GeneralCommands.java | 481 +++ .../worldedit/command/GenerationCommands.java | 407 +++ .../worldedit/command/HistoryCommands.java | 146 + .../InsufficientArgumentsException.java | 36 + .../command/LegacySnapshotCommands.java | 203 ++ .../command/LegacySnapshotUtilCommands.java | 132 + .../worldedit/command/NavigationCommands.java | 201 ++ .../worldedit/command/PaintBrushCommands.java | 149 + .../worldedit/command/RegionCommands.java | 566 ++++ .../worldedit/command/SchematicCommands.java | 464 +++ .../worldedit/command/ScriptingCommands.java | 112 + .../worldedit/command/SelectionCommands.java | 712 +++++ .../worldedit/command/SnapshotCommands.java | 344 ++ .../command/SnapshotUtilCommands.java | 140 + .../command/SuperPickaxeCommands.java | 99 + .../sk89q/worldedit/command/ToolCommands.java | 310 ++ .../worldedit/command/ToolUtilCommands.java | 141 + .../worldedit/command/UtilityCommands.java | 552 ++++ .../worldedit/command/WorldEditCommands.java | 208 ++ .../argument/AbstractDirectionConverter.java | 121 + .../worldedit/command/argument/Arguments.java | 32 + ..._AbstractDirectionConverter_direction.java | 54 + ...ractDirectionConverter_multiDirection.java | 54 + .../command/argument/BooleanConverter.java | 45 + .../argument/Chunk3dVectorConverter.java | 96 + .../CommaSeparatedValuesConverter.java | 92 + .../command/argument/DirectionConverter.java | 54 + .../argument/DirectionVectorConverter.java | 49 + .../argument/EntityRemoverConverter.java | 70 + .../command/argument/EnumConverter.java | 84 + .../command/argument/FactoryConverter.java | 142 + .../command/argument/HeightConverter.java | 74 + .../command/argument/OffsetConverter.java | 139 + .../argument/RegionFactoryConverter.java | 49 + .../command/argument/RegistryConverter.java | 113 + .../command/argument/SelectorChoice.java | 33 + .../command/argument/SideEffectConverter.java | 73 + .../command/argument/VectorConverter.java | 114 + .../command/argument/WorldConverter.java | 81 + .../argument/ZonedDateTimeConverter.java | 61 + .../command/argument/package-info.java | 21 + .../command/factory/ItemUseFactory.java | 54 + .../command/factory/ReplaceFactory.java | 49 + .../command/factory/TreeGeneratorFactory.java | 44 + .../worldedit/command/tool/AreaPickaxe.java | 99 + .../command/tool/BlockDataCyler.java | 129 + .../worldedit/command/tool/BlockReplacer.java | 90 + .../worldedit/command/tool/BlockTool.java | 68 + .../worldedit/command/tool/BrushTool.java | 224 ++ .../worldedit/command/tool/DistanceWand.java | 88 + .../command/tool/DoubleActionBlockTool.java | 72 + .../command/tool/DoubleActionTraceTool.java | 43 + .../command/tool/FloatingTreeRemover.java | 159 + .../worldedit/command/tool/FloodFillTool.java | 117 + .../tool/InvalidToolBindException.java | 45 + .../command/tool/LongRangeBuildTool.java | 133 + .../command/tool/NavigationWand.java | 73 + .../worldedit/command/tool/QueryTool.java | 85 + .../command/tool/RecursivePickaxe.java | 121 + .../worldedit/command/tool/SelectionWand.java | 63 + .../worldedit/command/tool/SinglePickaxe.java | 68 + .../worldedit/command/tool/StackTool.java | 85 + .../sk89q/worldedit/command/tool/Tool.java | 39 + .../worldedit/command/tool/TraceTool.java | 39 + .../worldedit/command/tool/TreePlanter.java | 81 + .../worldedit/command/tool/brush/Brush.java | 43 + .../command/tool/brush/ButcherBrush.java | 49 + .../command/tool/brush/ClipboardBrush.java | 79 + .../command/tool/brush/CylinderBrush.java | 44 + .../command/tool/brush/GravityBrush.java | 105 + .../tool/brush/HollowCylinderBrush.java | 44 + .../command/tool/brush/HollowSphereBrush.java | 37 + .../tool/brush/ImageHeightmapBrush.java | 83 + .../tool/brush/OperationFactoryBrush.java | 60 + .../command/tool/brush/SmoothBrush.java | 62 + .../command/tool/brush/SphereBrush.java | 37 + .../command/util/AsyncCommandBuilder.java | 222 ++ .../command/util/CommandPermissions.java | 39 + .../CommandPermissionsConditionGenerator.java | 46 + .../command/util/CreatureButcher.java | 130 + .../worldedit/command/util/EntityRemover.java | 157 + .../command/util/FutureProgressListener.java | 76 + .../worldedit/command/util/HookMode.java | 24 + .../sk89q/worldedit/command/util/Logging.java | 68 + .../command/util/MessageTimerTask.java | 66 + .../command/util/PermissionCondition.java | 50 + .../command/util/PrintCommandHelp.java | 166 + .../util/SubCommandPermissionCondition.java | 69 + .../command/util/SuggestionHelper.java | 179 ++ .../util/WorldEditAsyncCommandBuilder.java | 52 + .../sk89q/worldedit/entity/BaseEntity.java | 104 + .../com/sk89q/worldedit/entity/Entity.java | 57 + .../com/sk89q/worldedit/entity/Player.java | 332 ++ .../entity/metadata/EntityProperties.java | 171 + .../worldedit/event/AbstractCancellable.java | 39 + .../sk89q/worldedit/event/Cancellable.java | 42 + .../java/com/sk89q/worldedit/event/Event.java | 26 + .../event/extent/EditSessionEvent.java | 180 ++ .../event/platform/BlockInteractEvent.java | 119 + .../event/platform/CommandEvent.java | 67 + .../platform/CommandSuggestionEvent.java | 96 + .../platform/ConfigurationLoadEvent.java | 53 + .../worldedit/event/platform/InputType.java | 37 + .../worldedit/event/platform/Interaction.java | 37 + .../event/platform/PlatformEvent.java | 40 + .../platform/PlatformInitializeEvent.java | 31 + .../event/platform/PlatformReadyEvent.java | 31 + .../event/platform/PlatformUnreadyEvent.java | 31 + .../platform/PlatformsRegisteredEvent.java | 28 + .../event/platform/PlayerInputEvent.java | 78 + .../event/platform/SessionIdleEvent.java | 45 + .../extension/factory/BlockFactory.java | 68 + .../extension/factory/ItemFactory.java | 38 + .../extension/factory/MaskFactory.java | 129 + .../extension/factory/PatternFactory.java | 54 + .../factory/parser/DefaultBlockParser.java | 419 +++ .../factory/parser/DefaultItemParser.java | 106 + .../factory/parser/mask/AirMaskParser.java | 50 + .../factory/parser/mask/BiomeMaskParser.java | 84 + .../parser/mask/BlockCategoryMaskParser.java | 62 + .../parser/mask/BlockStateMaskParser.java | 64 + .../factory/parser/mask/BlocksMaskParser.java | 64 + .../parser/mask/ExistingMaskParser.java | 49 + .../parser/mask/ExposedMaskParser.java | 53 + .../parser/mask/ExpressionMaskParser.java | 73 + .../parser/mask/LazyRegionMaskParser.java | 49 + .../factory/parser/mask/NegateMaskParser.java | 61 + .../factory/parser/mask/NoiseMaskParser.java | 57 + .../factory/parser/mask/OffsetMaskParser.java | 66 + .../factory/parser/mask/RegionMaskParser.java | 55 + .../factory/parser/mask/SolidMaskParser.java | 49 + .../pattern/BlockCategoryPatternParser.java | 84 + .../pattern/ClipboardPatternParser.java | 108 + .../parser/pattern/RandomPatternParser.java | 96 + .../pattern/RandomStatePatternParser.java | 69 + .../pattern/SingleBlockPatternParser.java | 46 + .../TypeOrStateApplyingPatternParser.java | 124 + .../input/DisallowedUsageException.java | 69 + .../extension/input/InputParseException.java | 70 + .../extension/input/NoMatchException.java | 69 + .../extension/input/ParserContext.java | 252 ++ .../platform/AbstractCommandBlockActor.java | 49 + .../platform/AbstractNonPlayerActor.java | 51 + .../extension/platform/AbstractPlatform.java | 91 + .../platform/AbstractPlayerActor.java | 570 ++++ .../worldedit/extension/platform/Actor.java | 172 + .../extension/platform/Capability.java | 136 + .../extension/platform/Locatable.java | 87 + .../extension/platform/MultiUserPlatform.java | 36 + .../platform/NoCapablePlatformException.java | 42 + .../extension/platform/Platform.java | 218 ++ .../platform/PlatformCommandManager.java | 579 ++++ .../extension/platform/PlatformManager.java | 442 +++ .../extension/platform/PlayerProxy.java | 201 ++ .../extension/platform/Preference.java | 59 + .../extension/platform/Watchdog.java | 29 + .../permission/ActorSelectorLimits.java | 86 + .../permission/OverridePermissions.java | 32 + .../extent/AbstractBufferingExtent.java | 102 + .../extent/AbstractDelegateExtent.java | 141 + .../worldedit/extent/ChangeSetExtent.java | 149 + .../com/sk89q/worldedit/extent/Extent.java | 92 + .../sk89q/worldedit/extent/InputExtent.java | 103 + .../sk89q/worldedit/extent/MaskingExtent.java | 72 + .../sk89q/worldedit/extent/NullExtent.java | 108 + .../sk89q/worldedit/extent/OutputExtent.java | 119 + .../sk89q/worldedit/extent/TracingExtent.java | 113 + .../worldedit/extent/buffer/ExtentBuffer.java | 84 + .../extent/buffer/ForgetfulExtentBuffer.java | 190 ++ .../extent/cache/LastAccessExtentCache.java | 97 + .../extent/clipboard/BlockArrayClipboard.java | 220 ++ .../worldedit/extent/clipboard/Clipboard.java | 71 + .../extent/clipboard/StoredEntity.java | 81 + .../clipboard/io/BuiltInClipboardFormat.java | 147 + .../extent/clipboard/io/ClipboardFormat.java | 87 + .../extent/clipboard/io/ClipboardFormats.java | 126 + .../extent/clipboard/io/ClipboardReader.java | 51 + .../extent/clipboard/io/ClipboardWriter.java | 42 + .../clipboard/io/MCEditSchematicReader.java | 412 +++ .../clipboard/io/NBTSchematicReader.java | 61 + .../clipboard/io/SpongeSchematicReader.java | 399 +++ .../clipboard/io/SpongeSchematicWriter.java | 289 ++ .../BannerBlockCompatibilityHandler.java | 163 + .../BedBlockCompatibilityHandler.java | 141 + .../EntityNBTCompatibilityHandler.java | 29 + .../FlowerPotCompatibilityHandler.java | 97 + .../legacycompat/NBTCompatibilityHandler.java | 31 + .../NoteBlockCompatibilityHandler.java | 63 + .../Pre13HangingCompatibilityHandler.java | 61 + .../SignCompatibilityHandler.java | 70 + .../SkullBlockCompatibilityHandler.java | 100 + .../worldedit/extent/inventory/BlockBag.java | 132 + .../extent/inventory/BlockBagException.java | 26 + .../extent/inventory/BlockBagExtent.java | 115 + .../inventory/OutOfBlocksException.java | 26 + .../extent/inventory/OutOfSpaceException.java | 48 + .../inventory/UnplaceableBlockException.java | 26 + .../extent/reorder/ChunkBatchingExtent.java | 115 + .../extent/reorder/MultiStageReorder.java | 286 ++ .../extent/reorder/ReorderingExtent.java | 34 + .../transform/BlockTransformExtent.java | 315 ++ .../extent/validation/BlockChangeLimiter.java | 89 + .../validation/DataValidatorExtent.java | 78 + .../extent/world/BiomeQuirkExtent.java | 50 + .../extent/world/BlockQuirkExtent.java | 69 + .../extent/world/ChunkLoadingExtent.java | 79 + .../extent/world/SideEffectExtent.java | 127 + .../extent/world/SurvivalModeExtent.java | 105 + .../extent/world/WatchdogTickingExtent.java | 128 + .../sk89q/worldedit/forge/CommandWrapper.java | 117 + .../sk89q/worldedit/forge/ForgeAdapter.java | 267 ++ .../worldedit/forge/ForgeBiomeRegistry.java | 69 + .../forge/ForgeBlockCategoryRegistry.java | 45 + .../forge/ForgeBlockCommandSender.java | 179 ++ .../worldedit/forge/ForgeBlockMaterial.java | 96 + .../worldedit/forge/ForgeBlockRegistry.java | 77 + .../worldedit/forge/ForgeCommandSender.java | 157 + .../worldedit/forge/ForgeConfiguration.java | 46 + .../sk89q/worldedit/forge/ForgeDataFixer.java | 2776 +++++++++++++++++ .../sk89q/worldedit/forge/ForgeEntity.java | 119 + .../forge/ForgeEntityProperties.java | 156 + .../forge/ForgeItemCategoryRegistry.java | 45 + .../worldedit/forge/ForgeItemRegistry.java | 44 + .../forge/ForgePermissionsProvider.java | 66 + .../sk89q/worldedit/forge/ForgePlatform.java | 257 ++ .../sk89q/worldedit/forge/ForgePlayer.java | 299 ++ .../worldedit/forge/ForgeRegistries.java | 75 + .../worldedit/forge/ForgeResourceLoader.java | 58 + .../sk89q/worldedit/forge/ForgeWatchdog.java | 38 + .../com/sk89q/worldedit/forge/ForgeWorld.java | 679 ++++ .../sk89q/worldedit/forge/ForgeWorldEdit.java | 452 +++ .../worldedit/forge/ThreadSafeCache.java | 80 + .../worldedit/forge/WorldEditFakePlayer.java | 65 + .../worldedit/forge/WorldEditGenListener.java | 45 + .../forge/internal/ExtendedChunk.java | 43 + .../forge/internal/ForgeTransmogrifier.java | 128 + .../internal/ForgeWorldNativeAccess.java | 167 + .../forge/internal/IPropertyAdapter.java | 70 + .../forge/internal/NBTConverter.java | 265 ++ .../forge/internal/TileEntityUtils.java | 55 + .../mixin/AccessorServerPlayerGameMode.java | 31 + .../mixin/MixinLevelChunkSetBlockHook.java | 85 + .../MixinServerGamePacketListenerImpl.java | 59 + .../forge/net/handler/PacketHandlerUtil.java | 45 + .../forge/net/handler/WECUIPacketHandler.java | 60 + .../function/CombinedRegionFunction.java | 94 + .../sk89q/worldedit/function/Contextual.java | 26 + .../sk89q/worldedit/function/EditContext.java | 73 + .../worldedit/function/EntityFunction.java | 39 + .../function/FlatRegionFunction.java | 41 + .../function/FlatRegionMaskingFilter.java | 57 + .../worldedit/function/GroundFunction.java | 94 + .../worldedit/function/ItemUseFunction.java | 47 + .../worldedit/function/LayerFunction.java | 52 + .../worldedit/function/RegionFunction.java | 39 + .../function/RegionMaskingFilter.java | 56 + .../function/biome/BiomeReplace.java | 78 + .../function/biome/ExtentBiomeCopy.java | 110 + .../block/BlockDistributionCounter.java | 72 + .../function/block/BlockReplace.java | 56 + .../worldedit/function/block/Counter.java | 49 + .../function/block/ExtentBlockCopy.java | 117 + .../worldedit/function/block/Naturalizer.java | 103 + .../function/block/SnowSimulator.java | 138 + .../function/entity/ExtentEntityCopy.java | 192 ++ .../worldedit/function/factory/Apply.java | 66 + .../function/factory/ApplyLayer.java | 65 + .../function/factory/ApplyRegion.java | 59 + .../function/factory/BiomeFactory.java | 45 + .../worldedit/function/factory/Deform.java | 207 ++ .../worldedit/function/factory/Paint.java | 79 + .../worldedit/function/factory/Snow.java | 44 + .../function/generator/FloraGenerator.java | 119 + .../function/generator/ForestGenerator.java | 74 + .../generator/GardenPatchGenerator.java | 215 ++ .../function/mask/AbstractExtentMask.java | 61 + .../worldedit/function/mask/AbstractMask.java | 26 + .../function/mask/AbstractMask2D.java | 26 + .../worldedit/function/mask/BiomeMask.java | 105 + .../worldedit/function/mask/BiomeMask2D.java | 101 + .../function/mask/BlockCategoryMask.java | 53 + .../worldedit/function/mask/BlockMask.java | 114 + .../function/mask/BlockStateMask.java | 75 + .../function/mask/BlockTypeMask.java | 105 + .../function/mask/BoundedHeightMask.java | 60 + .../function/mask/ExistingBlockMask.java | 53 + .../function/mask/ExpressionMask.java | 92 + .../function/mask/ExpressionMask2D.java | 75 + .../sk89q/worldedit/function/mask/Mask.java | 47 + .../sk89q/worldedit/function/mask/Mask2D.java | 37 + .../function/mask/MaskIntersection.java | 115 + .../function/mask/MaskIntersection2D.java | 100 + .../worldedit/function/mask/MaskUnion.java | 81 + .../worldedit/function/mask/MaskUnion2D.java | 62 + .../sk89q/worldedit/function/mask/Masks.java | 188 ++ .../worldedit/function/mask/NoiseFilter.java | 98 + .../function/mask/NoiseFilter2D.java | 90 + .../worldedit/function/mask/OffsetMask.java | 107 + .../worldedit/function/mask/OffsetMask2D.java | 94 + .../worldedit/function/mask/OffsetsMask.java | 249 ++ .../function/mask/OffsetsMask2D.java | 232 ++ .../worldedit/function/mask/RegionMask.java | 75 + .../function/mask/SolidBlockMask.java | 47 + .../function/operation/ChangeSetExecutor.java | 104 + .../function/operation/DelegateOperation.java | 67 + .../function/operation/ForwardExtentCopy.java | 347 +++ .../function/operation/Operation.java | 96 + .../function/operation/OperationQueue.java | 115 + .../function/operation/Operations.java | 81 + .../function/operation/RunContext.java | 38 + .../function/operation/SetBlockMap.java | 54 + .../function/operation/SetLocatedBlocks.java | 50 + .../pattern/AbstractExtentPattern.java | 39 + .../function/pattern/AbstractPattern.java | 26 + .../function/pattern/BiomePattern.java | 62 + .../function/pattern/BlockPattern.java | 71 + .../function/pattern/ClipboardPattern.java | 48 + .../ExtentBufferedCompositePattern.java | 66 + .../function/pattern/ExtentPattern.java | 32 + .../worldedit/function/pattern/Pattern.java | 61 + .../function/pattern/RandomPattern.java | 88 + .../function/pattern/RandomStatePattern.java | 45 + .../pattern/RepeatingExtentPattern.java | 97 + .../pattern/StateApplyingPattern.java | 54 + .../function/pattern/TypeApplyingPattern.java | 52 + .../function/pattern/WaterloggedRemover.java | 47 + .../function/util/FlatRegionOffset.java | 71 + .../worldedit/function/util/RegionOffset.java | 72 + .../function/visitor/BreadthFirstSearch.java | 190 ++ .../function/visitor/DownwardVisitor.java | 68 + .../function/visitor/EntityVisitor.java | 91 + .../function/visitor/FlatRegionVisitor.java | 92 + .../function/visitor/LayerVisitor.java | 129 + .../function/visitor/NonRisingVisitor.java | 50 + .../function/visitor/RecursiveVisitor.java | 52 + .../function/visitor/RegionVisitor.java | 81 + .../sk89q/worldedit/history/UndoContext.java | 54 + .../worldedit/history/change/BiomeChange.java | 98 + .../history/change/BiomeChange3D.java | 96 + .../worldedit/history/change/BlockChange.java | 97 + .../worldedit/history/change/Change.java | 49 + .../history/change/EntityCreate.java | 68 + .../history/change/EntityRemove.java | 65 + .../history/changeset/ArrayListHistory.java | 73 + .../changeset/BlockOptimizedHistory.java | 85 + .../history/changeset/ChangeSet.java | 80 + .../sk89q/worldedit/internal/Constants.java | 90 + .../internal/SchematicsEventListener.java | 47 + .../internal/annotation/Chunk3d.java | 41 + .../internal/annotation/ClipboardMask.java | 37 + .../internal/annotation/Direction.java | 41 + .../internal/annotation/MultiDirection.java | 37 + .../worldedit/internal/annotation/Offset.java | 38 + .../internal/annotation/OptionalArg.java | 38 + .../worldedit/internal/annotation/Radii.java | 40 + .../internal/annotation/Selection.java | 36 + .../internal/annotation/VertHeight.java | 36 + .../internal/anvil/ChunkDeleter.java | 362 +++ .../internal/anvil/ChunkDeletionInfo.java | 56 + .../internal/anvil/RegionAccess.java | 101 + .../internal/block/BlockStateIdAccess.java | 111 + .../internal/command/ActorAuthorizer.java | 40 + .../internal/command/CommandArgParser.java | 131 + .../command/CommandLoggingHandler.java | 155 + .../command/CommandRegistrationHandler.java | 51 + .../internal/command/CommandUtil.java | 296 ++ .../command/exception/ExceptionConverter.java | 52 + .../exception/ExceptionConverterHelper.java | 114 + .../command/exception/ExceptionMatch.java | 34 + .../WorldEditExceptionConverter.java | 188 ++ .../worldedit/internal/cui/CUIEvent.java | 27 + .../worldedit/internal/cui/CUIRegion.java | 66 + .../internal/cui/SelectionCylinderEvent.java | 52 + .../cui/SelectionEllipsoidPointEvent.java | 49 + .../internal/cui/SelectionMinMaxEvent.java | 45 + .../internal/cui/SelectionPoint2DEvent.java | 77 + .../internal/cui/SelectionPointEvent.java | 59 + .../internal/cui/SelectionPolygonEvent.java | 49 + .../internal/cui/SelectionShapeEvent.java | 40 + .../internal/cui/ServerCUIHandler.java | 172 + .../internal/event/InteractionDebouncer.java | 69 + .../expression/CompiledExpression.java | 29 + .../expression/EvaluationException.java | 47 + .../internal/expression/ExecutionData.java | 61 + .../internal/expression/Expression.java | 161 + .../expression/ExpressionEnvironment.java | 39 + .../expression/ExpressionException.java | 53 + .../internal/expression/ExpressionHelper.java | 162 + .../ExpressionTimeoutException.java | 29 + .../expression/ExpressionValidator.java | 68 + .../internal/expression/Functions.java | 386 +++ .../internal/expression/Identifiable.java | 61 + .../expression/LexerErrorListener.java | 31 + .../internal/expression/LexerException.java | 47 + .../internal/expression/LocalSlot.java | 69 + .../expression/ParserErrorListener.java | 31 + .../internal/expression/ParserException.java | 47 + .../internal/expression/SlotTable.java | 60 + .../expression/invoke/BreakException.java | 40 + .../expression/invoke/CompilingVisitor.java | 667 ++++ .../internal/expression/invoke/ExecNode.java | 34 + .../expression/invoke/ExpressionCompiler.java | 76 + .../expression/invoke/ExpressionHandles.java | 383 +++ .../expression/invoke/ReturnException.java | 41 + .../internal/helper/MCDirections.java | 191 ++ .../internal/registry/AbstractFactory.java | 103 + .../internal/registry/InputParser.java | 52 + .../internal/registry/SimpleInputParser.java | 81 + .../internal/util/AbstractAdapter.java | 52 + .../worldedit/internal/util/BiomeMath.java | 51 + .../internal/util/DeprecationUtil.java | 118 + .../internal/util/InfoEntryPoint.java | 88 + .../internal/util/LogManagerCompat.java | 44 + .../util/NonAbstractForCompatibility.java | 57 + .../util/RegionOptimizedVectorSorter.java | 216 ++ .../worldedit/internal/util/Substring.java | 105 + .../internal/wna/WorldNativeAccess.java | 196 ++ .../worldedit/internal/wna/package-info.java | 27 + .../com/sk89q/worldedit/math/BitMath.java | 52 + .../sk89q/worldedit/math/BlockVector2.java | 567 ++++ .../sk89q/worldedit/math/BlockVector3.java | 716 +++++ .../com/sk89q/worldedit/math/MathUtils.java | 126 + .../math/RegionOptimizedChunkComparator.java | 41 + .../math/RegionOptimizedComparator.java | 36 + .../com/sk89q/worldedit/math/Vector2.java | 491 +++ .../com/sk89q/worldedit/math/Vector3.java | 622 ++++ .../math/convolution/GaussianKernel.java | 52 + .../worldedit/math/convolution/HeightMap.java | 179 ++ .../math/convolution/HeightMapFilter.java | 129 + .../worldedit/math/convolution/Kernel.java | 75 + .../math/convolution/LinearKernel.java | 42 + .../sk89q/worldedit/math/geom/Polygons.java | 63 + .../math/interpolation/Interpolation.java | 76 + .../KochanekBartelsInterpolation.java | 261 ++ .../interpolation/LinearInterpolation.java | 163 + .../worldedit/math/interpolation/Node.java | 89 + .../ReparametrisingInterpolation.java | 166 + .../math/noise/JLibNoiseGenerator.java | 62 + .../worldedit/math/noise/NoiseGenerator.java | 48 + .../worldedit/math/noise/PerlinNoise.java | 76 + .../worldedit/math/noise/RandomNoise.java | 62 + .../math/noise/RidgedMultiFractalNoise.java | 68 + .../worldedit/math/noise/VoronoiNoise.java | 52 + .../math/transform/AffineTransform.java | 325 ++ .../math/transform/CombinedTransform.java | 99 + .../worldedit/math/transform/Identity.java | 53 + .../worldedit/math/transform/Transform.java | 61 + .../worldedit/math/transform/Transforms.java | 49 + .../worldedit/regions/AbstractFlatRegion.java | 40 + .../worldedit/regions/AbstractRegion.java | 217 ++ .../regions/ConvexPolyhedralRegion.java | 331 ++ .../sk89q/worldedit/regions/CuboidRegion.java | 432 +++ .../worldedit/regions/CylinderRegion.java | 358 +++ .../worldedit/regions/EllipsoidRegion.java | 236 ++ .../sk89q/worldedit/regions/FlatRegion.java | 46 + .../sk89q/worldedit/regions/NullRegion.java | 141 + .../worldedit/regions/Polygonal2DRegion.java | 450 +++ .../com/sk89q/worldedit/regions/Region.java | 193 ++ .../worldedit/regions/RegionIntersection.java | 140 + .../regions/RegionOperationException.java | 36 + .../worldedit/regions/RegionSelector.java | 199 ++ .../com/sk89q/worldedit/regions/Regions.java | 92 + .../worldedit/regions/TransformRegion.java | 191 ++ .../regions/factory/CuboidRegionFactory.java | 33 + .../factory/CylinderRegionFactory.java | 40 + .../regions/factory/RegionFactory.java | 29 + .../regions/factory/SphereRegionFactory.java | 34 + .../iterator/FlatRegion3DIterator.java | 89 + .../regions/iterator/FlatRegionIterator.java | 99 + .../regions/iterator/RegionIterator.java | 105 + .../worldedit/regions/polyhedron/Edge.java | 86 + .../regions/polyhedron/Triangle.java | 113 + .../ConvexPolyhedralRegionSelector.java | 274 ++ .../selector/CuboidRegionSelector.java | 318 ++ .../selector/CylinderRegionSelector.java | 310 ++ .../selector/EllipsoidRegionSelector.java | 295 ++ .../ExtendingCuboidRegionSelector.java | 154 + .../selector/Polygonal2DRegionSelector.java | 287 ++ .../regions/selector/RegionSelectorType.java | 65 + .../selector/SphereRegionSelector.java | 114 + .../limit/PermissiveSelectorLimits.java | 53 + .../selector/limit/SelectorLimits.java | 47 + .../regions/shape/ArbitraryBiomeShape.java | 158 + .../regions/shape/ArbitraryShape.java | 184 ++ .../worldedit/regions/shape/RegionShape.java | 45 + .../shape/WorldEditExpressionEnvironment.java | 89 + .../sk89q/worldedit/registry/Category.java | 67 + .../com/sk89q/worldedit/registry/Keyed.java | 31 + .../registry/NamespacedRegistry.java | 92 + .../sk89q/worldedit/registry/Registry.java | 80 + .../registry/state/AbstractProperty.java | 61 + .../registry/state/BooleanProperty.java | 40 + .../registry/state/DirectionalProperty.java | 43 + .../registry/state/EnumProperty.java | 39 + .../registry/state/IntegerProperty.java | 44 + .../worldedit/registry/state/Property.java | 56 + .../scripting/CraftScriptContext.java | 272 ++ .../scripting/CraftScriptEngine.java | 32 + .../scripting/CraftScriptEnvironment.java | 44 + .../MinecraftHidingClassShutter.java | 32 + .../scripting/RhinoContextFactory.java | 77 + .../scripting/RhinoCraftScriptEngine.java | 90 + .../worldedit/session/ClipboardHolder.java | 89 + .../session/MissingSessionException.java | 42 + .../sk89q/worldedit/session/PasteBuilder.java | 147 + .../sk89q/worldedit/session/SessionKey.java | 62 + .../worldedit/session/SessionManager.java | 403 +++ .../sk89q/worldedit/session/SessionOwner.java | 36 + .../session/TransientSessionException.java | 42 + .../worldedit/session/request/Request.java | 126 + .../session/request/RequestExtent.java | 114 + .../session/request/RequestSelection.java | 155 + .../session/storage/JsonFileSessionStore.java | 130 + .../session/storage/SessionStore.java | 57 + .../worldedit/session/storage/VoidStore.java | 41 + .../com/sk89q/worldedit/util/Countable.java | 72 + .../com/sk89q/worldedit/util/Direction.java | 280 ++ .../java/com/sk89q/worldedit/util/Enums.java | 55 + .../com/sk89q/worldedit/util/Faceted.java | 52 + .../sk89q/worldedit/util/FileDialogUtil.java | 96 + .../com/sk89q/worldedit/util/GuavaUtil.java | 34 + .../com/sk89q/worldedit/util/HandSide.java | 25 + .../sk89q/worldedit/util/Identifiable.java | 36 + .../sk89q/worldedit/util/LocatedBlock.java | 67 + .../com/sk89q/worldedit/util/Location.java | 384 +++ .../util/PropertiesConfiguration.java | 286 ++ .../com/sk89q/worldedit/util/SideEffect.java | 69 + .../sk89q/worldedit/util/SideEffectSet.java | 92 + .../com/sk89q/worldedit/util/TargetBlock.java | 254 ++ .../sk89q/worldedit/util/TreeGenerator.java | 276 ++ .../sk89q/worldedit/util/WeightedChoice.java | 116 + .../worldedit/util/YAMLConfiguration.java | 139 + .../worldedit/util/asset/AssetLoadTask.java | 55 + .../worldedit/util/asset/AssetLoader.java | 111 + .../worldedit/util/asset/AssetLoaders.java | 172 + .../util/asset/ImageHeightmapLoader.java | 55 + .../util/asset/holder/ImageHeightmap.java | 90 + .../util/auth/AuthorizationException.java | 54 + .../sk89q/worldedit/util/auth/Authorizer.java | 38 + .../worldedit/util/auth/NullAuthorizer.java | 35 + .../sk89q/worldedit/util/auth/Subject.java | 51 + .../worldedit/util/collection/BlockMap.java | 472 +++ .../util/collection/DoubleArrayList.java | 182 ++ .../util/collection/Int2BaseBlockMap.java | 211 ++ .../util/collection/LocatedBlockList.java | 92 + .../util/collection/LongPositionList.java | 91 + .../util/collection/MoreStreams.java | 83 + .../util/collection/PositionList.java | 47 + .../util/collection/VectorPositionList.java | 105 + .../util/concurrency/EvenMoreExecutors.java | 74 + .../util/concurrency/LazyReference.java | 75 + .../eventbus/AnnotatedSubscriberFinder.java | 81 + .../worldedit/util/eventbus/EventBus.java | 199 ++ .../worldedit/util/eventbus/EventHandler.java | 105 + .../util/eventbus/HierarchyCache.java | 66 + .../util/eventbus/MethodEventHandler.java | 86 + .../eventbus/MethodHandleEventHandler.java | 82 + .../worldedit/util/eventbus/Subscribe.java | 42 + .../eventbus/SubscriberFindingStrategy.java | 43 + .../util/formatting/WorldEditText.java | 53 + .../util/formatting/component/CodeFormat.java | 48 + .../formatting/component/CommandListBox.java | 107 + .../formatting/component/CommandUsageBox.java | 89 + .../formatting/component/ErrorFormat.java | 51 + .../component/InvalidComponentException.java | 35 + .../formatting/component/LabelFormat.java | 51 + .../util/formatting/component/MessageBox.java | 103 + .../formatting/component/PaginationBox.java | 161 + .../formatting/component/SideEffectBox.java | 93 + .../formatting/component/SubtleFormat.java | 51 + .../component/TextComponentProducer.java | 83 + .../util/formatting/component/TextUtils.java | 63 + .../worldedit/util/function/IOFunction.java | 44 + .../worldedit/util/function/IORunnable.java | 43 + .../util/function/LevenshteinDistance.java | 193 ++ .../util/gson/BlockVectorAdapter.java | 42 + .../sk89q/worldedit/util/gson/GsonUtil.java | 52 + .../worldedit/util/gson/VectorAdapter.java | 45 + .../com/sk89q/worldedit/util/io/Closer.java | 282 ++ .../util/io/ForwardSeekableInputStream.java | 102 + .../worldedit/util/io/ResourceLoader.java | 81 + .../util/io/WorldEditResourceLoader.java | 38 + .../worldedit/util/io/file/ArchiveDir.java | 33 + .../util/io/file/ArchiveNioSupport.java | 39 + .../util/io/file/ArchiveNioSupports.java | 94 + .../util/io/file/ArchiveUnpacker.java | 122 + .../util/io/file/AttributeTarget.java | 24 + .../file/FileSelectionAbortedException.java | 38 + .../util/io/file/FilenameException.java | 49 + .../io/file/FilenameResolutionException.java | 39 + .../io/file/InvalidFilenameException.java | 39 + .../worldedit/util/io/file/MorePaths.java | 83 + .../worldedit/util/io/file/SafeFiles.java | 199 ++ .../util/io/file/ZipArchiveNioSupport.java | 64 + .../util/lifecycle/ConstantLifecycled.java | 55 + .../util/lifecycle/FlatMapLifecycled.java | 80 + .../worldedit/util/lifecycle/Lifecycled.java | 151 + .../lifecycle/LifecycledCallbackHandler.java | 114 + .../util/lifecycle/MapLifecycled.java | 82 + .../util/lifecycle/SimpleLifecycled.java | 79 + .../sk89q/worldedit/util/lifecycle/Token.java | 33 + .../util/logging/DynamicStreamHandler.java | 179 ++ .../worldedit/util/logging/LogFormat.java | 83 + .../sk89q/worldedit/util/net/HttpRequest.java | 528 ++++ .../util/paste/ActorCallbackPaste.java | 80 + .../worldedit/util/paste/EngineHubPaste.java | 79 + .../sk89q/worldedit/util/paste/Paster.java | 29 + .../sk89q/worldedit/util/paste/Pasters.java | 44 + .../worldedit/util/report/ConfigReport.java | 32 + .../worldedit/util/report/DataReport.java | 181 ++ .../util/report/HierarchyObjectReport.java | 32 + .../sk89q/worldedit/util/report/Report.java | 26 + .../worldedit/util/report/ReportList.java | 186 ++ .../util/report/ShallowObjectReport.java | 60 + .../util/report/StackTraceReport.java | 64 + .../util/report/SystemInfoReport.java | 97 + .../worldedit/util/report/Unreported.java | 33 + .../worldedit/util/task/AbstractTask.java | 74 + .../util/task/FutureForwardingTask.java | 121 + .../worldedit/util/task/SimpleSupervisor.java | 59 + .../sk89q/worldedit/util/task/Supervisor.java | 44 + .../com/sk89q/worldedit/util/task/Task.java | 97 + .../util/task/TaskStateComparator.java | 43 + .../util/task/progress/Progress.java | 183 ++ .../util/task/progress/ProgressIterator.java | 100 + .../task/progress/ProgressObservable.java | 34 + .../util/time/FileNameDateTimeParser.java | 108 + .../util/time/ModificationDateTimeParser.java | 52 + .../util/time/SnapshotDateTimeParser.java | 45 + .../util/translation/TranslationManager.java | 274 ++ .../sk89q/worldedit/world/AbstractWorld.java | 185 ++ .../sk89q/worldedit/world/DataException.java | 35 + .../com/sk89q/worldedit/world/DataFixer.java | 53 + .../com/sk89q/worldedit/world/NbtValued.java | 63 + .../com/sk89q/worldedit/world/NullWorld.java | 184 ++ .../sk89q/worldedit/world/RegenOptions.java | 102 + .../java/com/sk89q/worldedit/world/World.java | 366 +++ .../world/WorldUnloadedException.java | 36 + .../worldedit/world/biome/BiomeData.java | 43 + .../worldedit/world/biome/BiomeName.java | 60 + .../worldedit/world/biome/BiomeType.java | 69 + .../worldedit/world/biome/BiomeTypes.java | 144 + .../sk89q/worldedit/world/biome/Biomes.java | 75 + .../worldedit/world/block/BaseBlock.java | 196 ++ .../world/block/BlockCategories.java | 217 ++ .../worldedit/world/block/BlockCategory.java | 59 + .../worldedit/world/block/BlockState.java | 273 ++ .../world/block/BlockStateHolder.java | 111 + .../worldedit/world/block/BlockType.java | 264 ++ .../worldedit/world/block/BlockTypes.java | 1047 +++++++ .../world/block/FuzzyBlockState.java | 151 + .../worldedit/world/chunk/AnvilChunk.java | 265 ++ .../worldedit/world/chunk/AnvilChunk13.java | 240 ++ .../worldedit/world/chunk/AnvilChunk16.java | 53 + .../worldedit/world/chunk/AnvilChunk18.java | 222 ++ .../sk89q/worldedit/world/chunk/Chunk.java | 40 + .../sk89q/worldedit/world/chunk/OldChunk.java | 201 ++ .../world/chunk/PackedIntArrayReader.java | 66 + .../worldedit/world/entity/EntityType.java | 68 + .../worldedit/world/entity/EntityTypes.java | 166 + .../world/fluid/FluidCategories.java | 46 + .../worldedit/world/fluid/FluidCategory.java | 48 + .../worldedit/world/fluid/FluidType.java | 63 + .../worldedit/world/fluid/FluidTypes.java | 49 + .../worldedit/world/gamemode/GameMode.java | 64 + .../worldedit/world/gamemode/GameModes.java | 47 + .../worldedit/world/item/ItemCategories.java | 146 + .../worldedit/world/item/ItemCategory.java | 60 + .../sk89q/worldedit/world/item/ItemType.java | 129 + .../sk89q/worldedit/world/item/ItemTypes.java | 1302 ++++++++ .../world/registry/BiomeRegistry.java | 53 + .../world/registry/BlockCategoryRegistry.java | 29 + .../world/registry/BlockMaterial.java | 161 + .../world/registry/BlockRegistry.java | 82 + .../world/registry/BundledBlockData.java | 136 + .../world/registry/BundledBlockRegistry.java | 83 + .../world/registry/BundledItemData.java | 139 + .../world/registry/BundledItemRegistry.java | 79 + .../world/registry/BundledRegistries.java | 124 + .../world/registry/CategoryRegistry.java | 43 + .../world/registry/EntityRegistry.java | 40 + .../world/registry/ItemCategoryRegistry.java | 29 + .../world/registry/ItemMaterial.java | 36 + .../world/registry/ItemRegistry.java | 69 + .../world/registry/LegacyMapper.java | 201 ++ .../world/registry/NullBiomeRegistry.java | 55 + .../registry/NullBlockCategoryRegistry.java | 33 + .../world/registry/NullEntityRegistry.java | 37 + .../registry/NullItemCategoryRegistry.java | 33 + .../registry/PassthroughBlockMaterial.java | 140 + .../registry/PassthroughItemMaterial.java | 45 + .../worldedit/world/registry/Registries.java | 69 + .../world/registry/SimpleBlockMaterial.java | 214 ++ .../world/registry/SimpleItemMaterial.java | 41 + .../snapshot/InvalidSnapshotException.java | 24 + .../snapshot/ModificationTimerParser.java | 35 + .../worldedit/world/snapshot/Snapshot.java | 220 ++ .../world/snapshot/SnapshotDateParser.java | 40 + .../world/snapshot/SnapshotRepository.java | 245 ++ .../world/snapshot/SnapshotRestore.java | 202 ++ .../world/snapshot/YYMMDDHHIISSParser.java | 51 + .../world/snapshot/experimental/Snapshot.java | 62 + .../experimental/SnapshotComparator.java | 35 + .../experimental/SnapshotDatabase.java | 81 + .../snapshot/experimental/SnapshotInfo.java | 94 + .../experimental/SnapshotRestore.java | 203 ++ .../fs/FileSystemSnapshotDatabase.java | 295 ++ .../experimental/fs/FolderSnapshot.java | 162 + .../snapshot/experimental/package-info.java | 30 + .../worldedit/world/storage/ChunkStore.java | 112 + .../world/storage/ChunkStoreException.java | 34 + .../world/storage/ChunkStoreHelper.java | 131 + .../world/storage/FileLegacyChunkStore.java | 70 + .../world/storage/FileMcRegionChunkStore.java | 76 + .../world/storage/InvalidFormatException.java | 30 + .../world/storage/LegacyChunkStore.java | 99 + .../world/storage/McRegionChunkStore.java | 92 + .../world/storage/McRegionReader.java | 193 ++ .../world/storage/MissingChunkException.java | 49 + .../world/storage/MissingWorldException.java | 54 + .../world/storage/NBTConversions.java | 58 + .../storage/TrueZipLegacyChunkStore.java | 158 + .../storage/TrueZipMcRegionChunkStore.java | 176 ++ .../world/storage/ZippedLegacyChunkStore.java | 153 + .../storage/ZippedMcRegionChunkStore.java | 162 + .../worldedit/world/weather/WeatherType.java | 64 + .../worldedit/world/weather/WeatherTypes.java | 45 + .../resources/META-INF/accesstransformer.cfg | 11 + src/main/resources/META-INF/mods.toml | 87 +- .../worldedit/world/registry/blocks.114.json | 1 + .../worldedit/world/registry/blocks.115.json | 1 + .../worldedit/world/registry/blocks.116.json | 1 + .../worldedit/world/registry/blocks.117.json | 1 + .../worldedit/world/registry/blocks.119.json | 1 + .../worldedit/world/registry/blocks.120.json | 1 + .../worldedit/world/registry/blocks.json | 1 + .../worldedit/world/registry/items.114.json | 1 + .../worldedit/world/registry/items.115.json | 1 + .../worldedit/world/registry/items.116.json | 1 + .../worldedit/world/registry/items.117.json | 1 + .../worldedit/world/registry/items.119.json | 1 + .../worldedit/world/registry/items.120.json | 1 + .../sk89q/worldedit/world/registry/items.json | 1 + .../worldedit/world/registry/legacy.json | 1 + .../resources/defaults/worldedit.properties | 33 + src/main/resources/lang/strings.json | 450 +++ src/main/resources/pack.mcmeta | 12 +- .../resources/worldedit-forge.mixins.json | 16 + src/main/resources/worldedit-icon.png | Bin 0 -> 5636 bytes 833 files changed, 99676 insertions(+), 263 deletions(-) create mode 100644 src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 delete mode 100644 src/main/java/com/example/examplemod/Config.java delete mode 100644 src/main/java/com/example/examplemod/ExampleMod.java create mode 100644 src/main/java/com/sk89q/jnbt/ByteArrayTag.java create mode 100644 src/main/java/com/sk89q/jnbt/ByteTag.java create mode 100644 src/main/java/com/sk89q/jnbt/CompoundTag.java create mode 100644 src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java create mode 100644 src/main/java/com/sk89q/jnbt/DoubleTag.java create mode 100644 src/main/java/com/sk89q/jnbt/EndTag.java create mode 100644 src/main/java/com/sk89q/jnbt/FloatTag.java create mode 100644 src/main/java/com/sk89q/jnbt/IntArrayTag.java create mode 100644 src/main/java/com/sk89q/jnbt/IntTag.java create mode 100644 src/main/java/com/sk89q/jnbt/ListTag.java create mode 100644 src/main/java/com/sk89q/jnbt/ListTagBuilder.java create mode 100644 src/main/java/com/sk89q/jnbt/LongArrayTag.java create mode 100644 src/main/java/com/sk89q/jnbt/LongTag.java create mode 100644 src/main/java/com/sk89q/jnbt/NBTConstants.java create mode 100644 src/main/java/com/sk89q/jnbt/NBTInputStream.java create mode 100644 src/main/java/com/sk89q/jnbt/NBTOutputStream.java create mode 100644 src/main/java/com/sk89q/jnbt/NBTUtils.java create mode 100644 src/main/java/com/sk89q/jnbt/NamedTag.java create mode 100644 src/main/java/com/sk89q/jnbt/ShortTag.java create mode 100644 src/main/java/com/sk89q/jnbt/StringTag.java create mode 100644 src/main/java/com/sk89q/jnbt/Tag.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/Command.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/CommandAlias.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/CommandException.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/CommandLocals.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/CommandPermissions.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/CommandPermissionsException.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/CommandUsageException.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/Console.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/Injector.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/MissingNestedCommandException.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/NestedCommand.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/SimpleInjector.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/SuggestionContext.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/UnhandledCommandException.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/WrappedCommandException.java create mode 100644 src/main/java/com/sk89q/minecraft/util/commands/package-info.java create mode 100644 src/main/java/com/sk89q/util/ReflectionUtil.java create mode 100644 src/main/java/com/sk89q/util/StringUtil.java create mode 100644 src/main/java/com/sk89q/util/yaml/YAMLFormat.java create mode 100644 src/main/java/com/sk89q/util/yaml/YAMLNode.java create mode 100644 src/main/java/com/sk89q/util/yaml/YAMLProcessor.java create mode 100644 src/main/java/com/sk89q/util/yaml/YAMLProcessorException.java create mode 100644 src/main/java/com/sk89q/worldedit/DisallowedItemException.java create mode 100644 src/main/java/com/sk89q/worldedit/EditSession.java create mode 100644 src/main/java/com/sk89q/worldedit/EditSessionBuilder.java create mode 100644 src/main/java/com/sk89q/worldedit/EditSessionFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/EmptyClipboardException.java create mode 100644 src/main/java/com/sk89q/worldedit/IncompleteRegionException.java create mode 100644 src/main/java/com/sk89q/worldedit/InvalidItemException.java create mode 100644 src/main/java/com/sk89q/worldedit/LocalConfiguration.java create mode 100644 src/main/java/com/sk89q/worldedit/LocalSession.java create mode 100644 src/main/java/com/sk89q/worldedit/MaxBrushRadiusException.java create mode 100644 src/main/java/com/sk89q/worldedit/MaxChangedBlocksException.java create mode 100644 src/main/java/com/sk89q/worldedit/MaxRadiusException.java create mode 100644 src/main/java/com/sk89q/worldedit/MissingWorldException.java create mode 100644 src/main/java/com/sk89q/worldedit/NotABlockException.java create mode 100644 src/main/java/com/sk89q/worldedit/TracedEditSession.java create mode 100644 src/main/java/com/sk89q/worldedit/UnknownDirectionException.java create mode 100644 src/main/java/com/sk89q/worldedit/UnknownItemException.java create mode 100644 src/main/java/com/sk89q/worldedit/WorldEdit.java create mode 100644 src/main/java/com/sk89q/worldedit/WorldEditException.java create mode 100644 src/main/java/com/sk89q/worldedit/WorldEditManifest.java create mode 100644 src/main/java/com/sk89q/worldedit/blocks/BaseItem.java create mode 100644 src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java create mode 100644 src/main/java/com/sk89q/worldedit/blocks/Blocks.java create mode 100644 src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java create mode 100644 src/main/java/com/sk89q/worldedit/blocks/SignBlock.java create mode 100644 src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java create mode 100644 src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java create mode 100644 src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/BiomeCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/BrushCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/ChunkCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/ExpandCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java create mode 100644 src/main/java/com/sk89q/worldedit/command/GeneralCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/GenerationCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/HistoryCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/InsufficientArgumentsException.java create mode 100644 src/main/java/com/sk89q/worldedit/command/LegacySnapshotCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/LegacySnapshotUtilCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/NavigationCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/RegionCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/SchematicCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/SelectionCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/ToolCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/UtilityCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/AbstractDirectionConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/Arguments.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/AutoAnnotation_AbstractDirectionConverter_direction.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/AutoAnnotation_AbstractDirectionConverter_multiDirection.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/Chunk3dVectorConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/DirectionVectorConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/HeightConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/OffsetConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/SideEffectConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/argument/package-info.java create mode 100644 src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/InvalidToolBindException.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/NavigationWand.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/StackTool.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/Tool.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/ImageHeightmapBrush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/OperationFactoryBrush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/SmoothBrush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/CommandPermissions.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/FutureProgressListener.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/HookMode.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/Logging.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/MessageTimerTask.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java create mode 100644 src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java create mode 100644 src/main/java/com/sk89q/worldedit/entity/BaseEntity.java create mode 100644 src/main/java/com/sk89q/worldedit/entity/Entity.java create mode 100644 src/main/java/com/sk89q/worldedit/entity/Player.java create mode 100644 src/main/java/com/sk89q/worldedit/entity/metadata/EntityProperties.java create mode 100644 src/main/java/com/sk89q/worldedit/event/AbstractCancellable.java create mode 100644 src/main/java/com/sk89q/worldedit/event/Cancellable.java create mode 100644 src/main/java/com/sk89q/worldedit/event/Event.java create mode 100644 src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/BlockInteractEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/CommandEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/ConfigurationLoadEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/InputType.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/Interaction.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/PlatformEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/PlatformInitializeEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/PlatformReadyEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/PlatformUnreadyEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/PlatformsRegisteredEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/PlayerInputEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/event/platform/SessionIdleEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/AirMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExposedMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/LazyRegionMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NegateMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NoiseMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/RegionMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomPatternParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/input/DisallowedUsageException.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/input/InputParseException.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/input/NoMatchException.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/AbstractCommandBlockActor.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/Actor.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/Capability.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/Locatable.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/MultiUserPlatform.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/NoCapablePlatformException.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/Platform.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/Preference.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/permission/ActorSelectorLimits.java create mode 100644 src/main/java/com/sk89q/worldedit/extension/platform/permission/OverridePermissions.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/Extent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/InputExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/NullExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/OutputExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/TracingExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/cache/LastAccessExtentCache.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/StoredEntity.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagException.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/inventory/OutOfBlocksException.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/inventory/OutOfSpaceException.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/inventory/UnplaceableBlockException.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/reorder/ReorderingExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/world/BiomeQuirkExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/world/BlockQuirkExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/world/SideEffectExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeBlockCommandSender.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeCommandSender.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeConfiguration.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeRegistries.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeResourceLoader.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/WorldEditGenListener.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/internal/ExtendedChunk.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/internal/ForgeTransmogrifier.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/internal/ForgeWorldNativeAccess.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/internal/IPropertyAdapter.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/internal/TileEntityUtils.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/mixin/AccessorServerPlayerGameMode.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/mixin/MixinLevelChunkSetBlockHook.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/mixin/MixinServerGamePacketListenerImpl.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java create mode 100644 src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/function/CombinedRegionFunction.java create mode 100644 src/main/java/com/sk89q/worldedit/function/Contextual.java create mode 100644 src/main/java/com/sk89q/worldedit/function/EditContext.java create mode 100644 src/main/java/com/sk89q/worldedit/function/EntityFunction.java create mode 100644 src/main/java/com/sk89q/worldedit/function/FlatRegionFunction.java create mode 100644 src/main/java/com/sk89q/worldedit/function/FlatRegionMaskingFilter.java create mode 100644 src/main/java/com/sk89q/worldedit/function/GroundFunction.java create mode 100644 src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java create mode 100644 src/main/java/com/sk89q/worldedit/function/LayerFunction.java create mode 100644 src/main/java/com/sk89q/worldedit/function/RegionFunction.java create mode 100644 src/main/java/com/sk89q/worldedit/function/RegionMaskingFilter.java create mode 100644 src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java create mode 100644 src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java create mode 100644 src/main/java/com/sk89q/worldedit/function/block/BlockDistributionCounter.java create mode 100644 src/main/java/com/sk89q/worldedit/function/block/BlockReplace.java create mode 100644 src/main/java/com/sk89q/worldedit/function/block/Counter.java create mode 100644 src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java create mode 100644 src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java create mode 100644 src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java create mode 100644 src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java create mode 100644 src/main/java/com/sk89q/worldedit/function/factory/Apply.java create mode 100644 src/main/java/com/sk89q/worldedit/function/factory/ApplyLayer.java create mode 100644 src/main/java/com/sk89q/worldedit/function/factory/ApplyRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/function/factory/BiomeFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/function/factory/Deform.java create mode 100644 src/main/java/com/sk89q/worldedit/function/factory/Paint.java create mode 100644 src/main/java/com/sk89q/worldedit/function/factory/Snow.java create mode 100644 src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java create mode 100644 src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java create mode 100644 src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/AbstractMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/AbstractMask2D.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/BiomeMask2D.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/Mask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/Mask2D.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection2D.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/Masks.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/OffsetsMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/OffsetsMask2D.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java create mode 100644 src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java create mode 100644 src/main/java/com/sk89q/worldedit/function/operation/DelegateOperation.java create mode 100644 src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java create mode 100644 src/main/java/com/sk89q/worldedit/function/operation/Operation.java create mode 100644 src/main/java/com/sk89q/worldedit/function/operation/OperationQueue.java create mode 100644 src/main/java/com/sk89q/worldedit/function/operation/Operations.java create mode 100644 src/main/java/com/sk89q/worldedit/function/operation/RunContext.java create mode 100644 src/main/java/com/sk89q/worldedit/function/operation/SetBlockMap.java create mode 100644 src/main/java/com/sk89q/worldedit/function/operation/SetLocatedBlocks.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/AbstractExtentPattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/AbstractPattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/BiomePattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/ExtentPattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/RandomStatePattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/TypeApplyingPattern.java create mode 100644 src/main/java/com/sk89q/worldedit/function/pattern/WaterloggedRemover.java create mode 100644 src/main/java/com/sk89q/worldedit/function/util/FlatRegionOffset.java create mode 100644 src/main/java/com/sk89q/worldedit/function/util/RegionOffset.java create mode 100644 src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java create mode 100644 src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java create mode 100644 src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java create mode 100644 src/main/java/com/sk89q/worldedit/function/visitor/FlatRegionVisitor.java create mode 100644 src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java create mode 100644 src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java create mode 100644 src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java create mode 100644 src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java create mode 100644 src/main/java/com/sk89q/worldedit/history/UndoContext.java create mode 100644 src/main/java/com/sk89q/worldedit/history/change/BiomeChange.java create mode 100644 src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java create mode 100644 src/main/java/com/sk89q/worldedit/history/change/BlockChange.java create mode 100644 src/main/java/com/sk89q/worldedit/history/change/Change.java create mode 100644 src/main/java/com/sk89q/worldedit/history/change/EntityCreate.java create mode 100644 src/main/java/com/sk89q/worldedit/history/change/EntityRemove.java create mode 100644 src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java create mode 100644 src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java create mode 100644 src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/Constants.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/SchematicsEventListener.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/annotation/Chunk3d.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/annotation/ClipboardMask.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/annotation/Direction.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/annotation/MultiDirection.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/annotation/Offset.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/annotation/OptionalArg.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/annotation/Radii.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/annotation/Selection.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/annotation/VertHeight.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/command/ActorAuthorizer.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionMatch.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/cui/CUIEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/cui/CUIRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/cui/SelectionMinMaxEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/cui/SelectionPolygonEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/cui/SelectionShapeEvent.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/CompiledExpression.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/EvaluationException.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/Expression.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/ExpressionTimeoutException.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/ExpressionValidator.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/Functions.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/Identifiable.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/LexerErrorListener.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/LexerException.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/ParserErrorListener.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/ParserException.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/invoke/BreakException.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionCompiler.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/expression/invoke/ReturnException.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/util/AbstractAdapter.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/util/BiomeMath.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/util/DeprecationUtil.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/util/InfoEntryPoint.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/util/LogManagerCompat.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/util/NonAbstractForCompatibility.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorter.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/util/Substring.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java create mode 100644 src/main/java/com/sk89q/worldedit/internal/wna/package-info.java create mode 100644 src/main/java/com/sk89q/worldedit/math/BitMath.java create mode 100644 src/main/java/com/sk89q/worldedit/math/BlockVector2.java create mode 100644 src/main/java/com/sk89q/worldedit/math/BlockVector3.java create mode 100644 src/main/java/com/sk89q/worldedit/math/MathUtils.java create mode 100644 src/main/java/com/sk89q/worldedit/math/RegionOptimizedChunkComparator.java create mode 100644 src/main/java/com/sk89q/worldedit/math/RegionOptimizedComparator.java create mode 100644 src/main/java/com/sk89q/worldedit/math/Vector2.java create mode 100644 src/main/java/com/sk89q/worldedit/math/Vector3.java create mode 100644 src/main/java/com/sk89q/worldedit/math/convolution/GaussianKernel.java create mode 100644 src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java create mode 100644 src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java create mode 100644 src/main/java/com/sk89q/worldedit/math/convolution/Kernel.java create mode 100644 src/main/java/com/sk89q/worldedit/math/convolution/LinearKernel.java create mode 100644 src/main/java/com/sk89q/worldedit/math/geom/Polygons.java create mode 100644 src/main/java/com/sk89q/worldedit/math/interpolation/Interpolation.java create mode 100644 src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java create mode 100644 src/main/java/com/sk89q/worldedit/math/interpolation/LinearInterpolation.java create mode 100644 src/main/java/com/sk89q/worldedit/math/interpolation/Node.java create mode 100644 src/main/java/com/sk89q/worldedit/math/interpolation/ReparametrisingInterpolation.java create mode 100644 src/main/java/com/sk89q/worldedit/math/noise/JLibNoiseGenerator.java create mode 100644 src/main/java/com/sk89q/worldedit/math/noise/NoiseGenerator.java create mode 100644 src/main/java/com/sk89q/worldedit/math/noise/PerlinNoise.java create mode 100644 src/main/java/com/sk89q/worldedit/math/noise/RandomNoise.java create mode 100644 src/main/java/com/sk89q/worldedit/math/noise/RidgedMultiFractalNoise.java create mode 100644 src/main/java/com/sk89q/worldedit/math/noise/VoronoiNoise.java create mode 100644 src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java create mode 100644 src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java create mode 100644 src/main/java/com/sk89q/worldedit/math/transform/Identity.java create mode 100644 src/main/java/com/sk89q/worldedit/math/transform/Transform.java create mode 100644 src/main/java/com/sk89q/worldedit/math/transform/Transforms.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/FlatRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/NullRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/Region.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/RegionOperationException.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/RegionSelector.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/Regions.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/TransformRegion.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/factory/CuboidRegionFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/factory/CylinderRegionFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/factory/RegionFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/factory/SphereRegionFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/polyhedron/Edge.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/polyhedron/Triangle.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/selector/limit/PermissiveSelectorLimits.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/selector/limit/SelectorLimits.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/shape/RegionShape.java create mode 100644 src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java create mode 100644 src/main/java/com/sk89q/worldedit/registry/Category.java create mode 100644 src/main/java/com/sk89q/worldedit/registry/Keyed.java create mode 100644 src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/registry/Registry.java create mode 100644 src/main/java/com/sk89q/worldedit/registry/state/AbstractProperty.java create mode 100644 src/main/java/com/sk89q/worldedit/registry/state/BooleanProperty.java create mode 100644 src/main/java/com/sk89q/worldedit/registry/state/DirectionalProperty.java create mode 100644 src/main/java/com/sk89q/worldedit/registry/state/EnumProperty.java create mode 100644 src/main/java/com/sk89q/worldedit/registry/state/IntegerProperty.java create mode 100644 src/main/java/com/sk89q/worldedit/registry/state/Property.java create mode 100644 src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java create mode 100644 src/main/java/com/sk89q/worldedit/scripting/CraftScriptEngine.java create mode 100644 src/main/java/com/sk89q/worldedit/scripting/CraftScriptEnvironment.java create mode 100644 src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java create mode 100644 src/main/java/com/sk89q/worldedit/scripting/RhinoContextFactory.java create mode 100644 src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java create mode 100644 src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java create mode 100644 src/main/java/com/sk89q/worldedit/session/MissingSessionException.java create mode 100644 src/main/java/com/sk89q/worldedit/session/PasteBuilder.java create mode 100644 src/main/java/com/sk89q/worldedit/session/SessionKey.java create mode 100644 src/main/java/com/sk89q/worldedit/session/SessionManager.java create mode 100644 src/main/java/com/sk89q/worldedit/session/SessionOwner.java create mode 100644 src/main/java/com/sk89q/worldedit/session/TransientSessionException.java create mode 100644 src/main/java/com/sk89q/worldedit/session/request/Request.java create mode 100644 src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java create mode 100644 src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java create mode 100644 src/main/java/com/sk89q/worldedit/session/storage/JsonFileSessionStore.java create mode 100644 src/main/java/com/sk89q/worldedit/session/storage/SessionStore.java create mode 100644 src/main/java/com/sk89q/worldedit/session/storage/VoidStore.java create mode 100644 src/main/java/com/sk89q/worldedit/util/Countable.java create mode 100644 src/main/java/com/sk89q/worldedit/util/Direction.java create mode 100644 src/main/java/com/sk89q/worldedit/util/Enums.java create mode 100644 src/main/java/com/sk89q/worldedit/util/Faceted.java create mode 100644 src/main/java/com/sk89q/worldedit/util/FileDialogUtil.java create mode 100644 src/main/java/com/sk89q/worldedit/util/GuavaUtil.java create mode 100644 src/main/java/com/sk89q/worldedit/util/HandSide.java create mode 100644 src/main/java/com/sk89q/worldedit/util/Identifiable.java create mode 100644 src/main/java/com/sk89q/worldedit/util/LocatedBlock.java create mode 100644 src/main/java/com/sk89q/worldedit/util/Location.java create mode 100644 src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java create mode 100644 src/main/java/com/sk89q/worldedit/util/SideEffect.java create mode 100644 src/main/java/com/sk89q/worldedit/util/SideEffectSet.java create mode 100644 src/main/java/com/sk89q/worldedit/util/TargetBlock.java create mode 100644 src/main/java/com/sk89q/worldedit/util/TreeGenerator.java create mode 100644 src/main/java/com/sk89q/worldedit/util/WeightedChoice.java create mode 100644 src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java create mode 100644 src/main/java/com/sk89q/worldedit/util/asset/AssetLoadTask.java create mode 100644 src/main/java/com/sk89q/worldedit/util/asset/AssetLoader.java create mode 100644 src/main/java/com/sk89q/worldedit/util/asset/AssetLoaders.java create mode 100644 src/main/java/com/sk89q/worldedit/util/asset/ImageHeightmapLoader.java create mode 100644 src/main/java/com/sk89q/worldedit/util/asset/holder/ImageHeightmap.java create mode 100644 src/main/java/com/sk89q/worldedit/util/auth/AuthorizationException.java create mode 100644 src/main/java/com/sk89q/worldedit/util/auth/Authorizer.java create mode 100644 src/main/java/com/sk89q/worldedit/util/auth/NullAuthorizer.java create mode 100644 src/main/java/com/sk89q/worldedit/util/auth/Subject.java create mode 100644 src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java create mode 100644 src/main/java/com/sk89q/worldedit/util/collection/DoubleArrayList.java create mode 100644 src/main/java/com/sk89q/worldedit/util/collection/Int2BaseBlockMap.java create mode 100644 src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java create mode 100644 src/main/java/com/sk89q/worldedit/util/collection/LongPositionList.java create mode 100644 src/main/java/com/sk89q/worldedit/util/collection/MoreStreams.java create mode 100644 src/main/java/com/sk89q/worldedit/util/collection/PositionList.java create mode 100644 src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java create mode 100644 src/main/java/com/sk89q/worldedit/util/concurrency/EvenMoreExecutors.java create mode 100644 src/main/java/com/sk89q/worldedit/util/concurrency/LazyReference.java create mode 100644 src/main/java/com/sk89q/worldedit/util/eventbus/AnnotatedSubscriberFinder.java create mode 100644 src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java create mode 100644 src/main/java/com/sk89q/worldedit/util/eventbus/EventHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/util/eventbus/HierarchyCache.java create mode 100644 src/main/java/com/sk89q/worldedit/util/eventbus/MethodEventHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/util/eventbus/MethodHandleEventHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/util/eventbus/Subscribe.java create mode 100644 src/main/java/com/sk89q/worldedit/util/eventbus/SubscriberFindingStrategy.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/WorldEditText.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/InvalidComponentException.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/SideEffectBox.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java create mode 100644 src/main/java/com/sk89q/worldedit/util/formatting/component/TextUtils.java create mode 100644 src/main/java/com/sk89q/worldedit/util/function/IOFunction.java create mode 100644 src/main/java/com/sk89q/worldedit/util/function/IORunnable.java create mode 100644 src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java create mode 100644 src/main/java/com/sk89q/worldedit/util/gson/BlockVectorAdapter.java create mode 100644 src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java create mode 100644 src/main/java/com/sk89q/worldedit/util/gson/VectorAdapter.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/Closer.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/WorldEditResourceLoader.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/ArchiveDir.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/ArchiveNioSupport.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/ArchiveNioSupports.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/ArchiveUnpacker.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/AttributeTarget.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/FileSelectionAbortedException.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/FilenameException.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/FilenameResolutionException.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/InvalidFilenameException.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/MorePaths.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/SafeFiles.java create mode 100644 src/main/java/com/sk89q/worldedit/util/io/file/ZipArchiveNioSupport.java create mode 100644 src/main/java/com/sk89q/worldedit/util/lifecycle/ConstantLifecycled.java create mode 100644 src/main/java/com/sk89q/worldedit/util/lifecycle/FlatMapLifecycled.java create mode 100644 src/main/java/com/sk89q/worldedit/util/lifecycle/Lifecycled.java create mode 100644 src/main/java/com/sk89q/worldedit/util/lifecycle/LifecycledCallbackHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/util/lifecycle/MapLifecycled.java create mode 100644 src/main/java/com/sk89q/worldedit/util/lifecycle/SimpleLifecycled.java create mode 100644 src/main/java/com/sk89q/worldedit/util/lifecycle/Token.java create mode 100644 src/main/java/com/sk89q/worldedit/util/logging/DynamicStreamHandler.java create mode 100644 src/main/java/com/sk89q/worldedit/util/logging/LogFormat.java create mode 100644 src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java create mode 100644 src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java create mode 100644 src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java create mode 100644 src/main/java/com/sk89q/worldedit/util/paste/Paster.java create mode 100644 src/main/java/com/sk89q/worldedit/util/paste/Pasters.java create mode 100644 src/main/java/com/sk89q/worldedit/util/report/ConfigReport.java create mode 100644 src/main/java/com/sk89q/worldedit/util/report/DataReport.java create mode 100644 src/main/java/com/sk89q/worldedit/util/report/HierarchyObjectReport.java create mode 100644 src/main/java/com/sk89q/worldedit/util/report/Report.java create mode 100644 src/main/java/com/sk89q/worldedit/util/report/ReportList.java create mode 100644 src/main/java/com/sk89q/worldedit/util/report/ShallowObjectReport.java create mode 100644 src/main/java/com/sk89q/worldedit/util/report/StackTraceReport.java create mode 100644 src/main/java/com/sk89q/worldedit/util/report/SystemInfoReport.java create mode 100644 src/main/java/com/sk89q/worldedit/util/report/Unreported.java create mode 100644 src/main/java/com/sk89q/worldedit/util/task/AbstractTask.java create mode 100644 src/main/java/com/sk89q/worldedit/util/task/FutureForwardingTask.java create mode 100644 src/main/java/com/sk89q/worldedit/util/task/SimpleSupervisor.java create mode 100644 src/main/java/com/sk89q/worldedit/util/task/Supervisor.java create mode 100644 src/main/java/com/sk89q/worldedit/util/task/Task.java create mode 100644 src/main/java/com/sk89q/worldedit/util/task/TaskStateComparator.java create mode 100644 src/main/java/com/sk89q/worldedit/util/task/progress/Progress.java create mode 100644 src/main/java/com/sk89q/worldedit/util/task/progress/ProgressIterator.java create mode 100644 src/main/java/com/sk89q/worldedit/util/task/progress/ProgressObservable.java create mode 100644 src/main/java/com/sk89q/worldedit/util/time/FileNameDateTimeParser.java create mode 100644 src/main/java/com/sk89q/worldedit/util/time/ModificationDateTimeParser.java create mode 100644 src/main/java/com/sk89q/worldedit/util/time/SnapshotDateTimeParser.java create mode 100644 src/main/java/com/sk89q/worldedit/util/translation/TranslationManager.java create mode 100644 src/main/java/com/sk89q/worldedit/world/AbstractWorld.java create mode 100644 src/main/java/com/sk89q/worldedit/world/DataException.java create mode 100644 src/main/java/com/sk89q/worldedit/world/DataFixer.java create mode 100644 src/main/java/com/sk89q/worldedit/world/NbtValued.java create mode 100644 src/main/java/com/sk89q/worldedit/world/NullWorld.java create mode 100644 src/main/java/com/sk89q/worldedit/world/RegenOptions.java create mode 100644 src/main/java/com/sk89q/worldedit/world/World.java create mode 100644 src/main/java/com/sk89q/worldedit/world/WorldUnloadedException.java create mode 100644 src/main/java/com/sk89q/worldedit/world/biome/BiomeData.java create mode 100644 src/main/java/com/sk89q/worldedit/world/biome/BiomeName.java create mode 100644 src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java create mode 100644 src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java create mode 100644 src/main/java/com/sk89q/worldedit/world/biome/Biomes.java create mode 100644 src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java create mode 100644 src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java create mode 100644 src/main/java/com/sk89q/worldedit/world/block/BlockCategory.java create mode 100644 src/main/java/com/sk89q/worldedit/world/block/BlockState.java create mode 100644 src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java create mode 100644 src/main/java/com/sk89q/worldedit/world/block/BlockType.java create mode 100644 src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java create mode 100644 src/main/java/com/sk89q/worldedit/world/block/FuzzyBlockState.java create mode 100644 src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java create mode 100644 src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java create mode 100644 src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java create mode 100644 src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java create mode 100644 src/main/java/com/sk89q/worldedit/world/chunk/Chunk.java create mode 100644 src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java create mode 100644 src/main/java/com/sk89q/worldedit/world/chunk/PackedIntArrayReader.java create mode 100644 src/main/java/com/sk89q/worldedit/world/entity/EntityType.java create mode 100644 src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java create mode 100644 src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java create mode 100644 src/main/java/com/sk89q/worldedit/world/fluid/FluidCategory.java create mode 100644 src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java create mode 100644 src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java create mode 100644 src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java create mode 100644 src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java create mode 100644 src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java create mode 100644 src/main/java/com/sk89q/worldedit/world/item/ItemCategory.java create mode 100644 src/main/java/com/sk89q/worldedit/world/item/ItemType.java create mode 100644 src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BiomeRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BlockCategoryRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/BundledRegistries.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/EntityRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/ItemCategoryRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/ItemRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/NullBlockCategoryRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/NullEntityRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/NullItemCategoryRegistry.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/Registries.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java create mode 100644 src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/InvalidSnapshotException.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/ModificationTimerParser.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotDateParser.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/experimental/Snapshot.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotComparator.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotDatabase.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotInfo.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/experimental/fs/FileSystemSnapshotDatabase.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/experimental/fs/FolderSnapshot.java create mode 100644 src/main/java/com/sk89q/worldedit/world/snapshot/experimental/package-info.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreException.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/FileLegacyChunkStore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/FileMcRegionChunkStore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/InvalidFormatException.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/MissingChunkException.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/MissingWorldException.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/TrueZipLegacyChunkStore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/ZippedLegacyChunkStore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java create mode 100644 src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java create mode 100644 src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java create mode 100644 src/main/resources/META-INF/accesstransformer.cfg create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/blocks.114.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/blocks.115.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/blocks.116.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/blocks.117.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/blocks.119.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/blocks.120.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/blocks.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/items.114.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/items.115.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/items.116.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/items.117.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/items.119.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/items.120.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/items.json create mode 100644 src/main/resources/com/sk89q/worldedit/world/registry/legacy.json create mode 100644 src/main/resources/defaults/worldedit.properties create mode 100644 src/main/resources/lang/strings.json create mode 100644 src/main/resources/worldedit-forge.mixins.json create mode 100644 src/main/resources/worldedit-icon.png diff --git a/build.gradle b/build.gradle index ffc7a0f..1a24a56 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ plugins { id 'idea' id 'maven-publish' id 'net.neoforged.gradle.userdev' version '7.0.57' + id 'antlr' } version = mod_version @@ -72,6 +73,12 @@ runs { // Include resources generated by data generators. sourceSets.main.resources { srcDir 'src/generated/resources' } +repositories { + maven { + name 'EngineHub Repository' + url 'https://maven.enginehub.org/repo/' + } +} dependencies { // Specify the version of Minecraft to use. @@ -82,6 +89,29 @@ dependencies { // For all intends and purposes: You can treat this dependency as if it is a normal library you would use. implementation "net.neoforged:neoforge:${neo_version}" + implementation("net.kyori:text-api:${TEXT}") + implementation("net.kyori:text-serializer-gson:${TEXT}") + implementation("net.kyori:text-serializer-legacy:${TEXT}") + implementation("net.kyori:text-serializer-plain:${TEXT}") + implementation "com.sk89q.lib:jlibnoise:1.0.0" + implementation "org.enginehub.piston:core:${PISTON}" + implementation "org.enginehub.piston.core-ap:runtime:${PISTON}" + implementation "org.enginehub.piston:default-impl:${PISTON}" + implementation "org.yaml:snakeyaml:2.0" + implementation("org.enginehub.piston.core-ap:annotations:${PISTON}") + implementation("org.enginehub.piston.core-ap:processor:${PISTON}") + annotationProcessor("org.enginehub.piston.core-ap:annotations:${PISTON}") + annotationProcessor("org.enginehub.piston.core-ap:processor:${PISTON}") + implementation ("com.sk89q:jchronic:0.2.4a") { + exclude group: "junit", module: "junit" + } + compileOnly("com.google.auto.value:auto-value-annotations:${AUTO_VALUE}") + annotationProcessor("com.google.auto.value:auto-value:${AUTO_VALUE}") + antlr("org.antlr:antlr4:4.9.1") + implementation("org.antlr:antlr4-runtime:4.9.1") + compileOnly("de.schlichtherle:truezip:6.8.4") + implementation("org.mozilla:rhino-runtime:1.7.13") + // Example mod dependency with JEI // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime // compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}" @@ -123,6 +153,55 @@ tasks.withType(ProcessResources).configureEach { } } +tasks.named('generateGrammarSource', AntlrTask) { + def pkg = 'com.sk89q.worldedit.antlr' + outputDirectory = file("build/generated-src/antlr/main/${pkg.replace('.', '/')}") + arguments = [ + '-visitor', '-package', pkg, + '-Xexact-output-dir' + ] +} + +def altConfigFiles = { String artifactType -> + def deps = configurations.shade.incoming.dependencies.findAll { it instanceof ModuleDependency } + .collect { dependency -> + def depCopy = dependency.copy() + depCopy.artifact { + name = dependency.name + type = artifactType + extension = 'jar' + classifier = artifactType + } + depCopy + } + + files(configurations.detachedConfiguration(deps.toArray(new Dependency[0])) + .resolvedConfiguration.lenientConfiguration.artifacts.findAll { it.classifier == artifactType } + .collect { zipTree(it.file) }) +} + +tasks.register('sourcesJar', Jar) { + from { + altConfigFiles('sources') + } + archiveClassifier = 'sources' +} + +tasks.named('sourcesJar') { + mustRunAfter 'generateGrammarSource' +} + +plugins.withId('idea') { + idea { + module { + sourceDirs += files('src/main/antlr') + sourceDirs += files('build/generated-src/antlr/main') + generatedSourceDirs += files('build/generated-src/antlr/main') + } + } +} + + // Example configuration to allow publishing using the maven-publish plugin publishing { publications { diff --git a/gradle.properties b/gradle.properties index 01edc03..7aa6c32 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,15 +6,16 @@ org.gradle.debug=false ## Environment Properties # The Minecraft version must agree with the Neo version to get a valid artifact -minecraft_version=1.20.2 +minecraft_version=1.20.4 # The Minecraft version range can use any release version of Minecraft as bounds. # Snapshots, pre-releases, and release candidates are not guaranteed to sort properly # as they do not follow standard versioning conventions. -minecraft_version_range=[1.20.2,1.21) +minecraft_version_range=[1.20.4,1.21) # The Neo version must agree with the Minecraft version to get a valid artifact -neo_version=20.2.86 +#neo_version=20.4.42-beta +neo_version=20.4.0-beta # The Neo version range can use any version of Neo as bounds or match the loader version range -neo_version_range=[20.2,) +neo_version_range=[20.5,) # The loader version range can only use the major version of Neo/FML as bounds loader_version_range=[1,) @@ -39,3 +40,8 @@ mod_authors=YourNameHere, OtherNameHere mod_description=Example mod description.\nNewline characters can be used and will be replaced properly. # Pack version - this changes each minecraft release, in general. pack_format_number=18 + + +PISTON=0.5.7 +AUTO_VALUE=1.9 +TEXT=3.0.4 diff --git a/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 b/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 new file mode 100644 index 0000000..2c2e949 --- /dev/null +++ b/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 @@ -0,0 +1,237 @@ +grammar Expression; + +// Lexer tokens: + +PLUS : '+' ; +MINUS : '-' ; +TIMES : '*' ; +DIVIDE : '/' ; +MODULO : '%' ; +POWER : '^' | '**' ; +LEFT_SHIFT : '<<' ; +RIGHT_SHIFT : '>>' ; +ASSIGN : '=' ; +COMPLEMENT : '~' ; + +PLUS_ASSIGN : '+=' ; +MINUS_ASSIGN : '-=' ; +TIMES_ASSIGN : '*=' ; +DIVIDE_ASSIGN : '/=' ; +MODULO_ASSIGN : '%=' ; +POWER_ASSIGN : '^=' ; + +EQUAL : '==' ; +NOT_EQUAL : '!=' ; +NEAR : '~=' ; +LESS_THAN : '<' ; +LESS_THAN_OR_EQUAL : '<=' ; +GREATER_THAN : '>' ; +GREATER_THAN_OR_EQUAL : '>=' ; +// SC = "Short Circuit" +// Non-SC variants not currently implemented. +AND_SC : '&&' ; +OR_SC : '||' ; + +INCREMENT : '++' ; +DECREMENT : '--' ; + +COMMA : ',' ; +OPEN_PAREN : '(' ; +CLOSE_PAREN : ')' ; +OPEN_BRACKET : '{' ; +CLOSE_BRACKET : '}' ; +SEMI_COLON : ';' ; +QUESTION_MARK : '?' ; +COLON : ':' ; +EXCLAMATION_MARK : '!' ; + +IF : 'if' ; +ELSE : 'else' ; +WHILE : 'while' ; +DO : 'do' ; +FOR : 'for' ; +BREAK : 'break' ; +CONTINUE : 'continue' ; +RETURN : 'return' ; +SWITCH : 'switch' ; +CASE : 'case' ; +DEFAULT : 'default' ; + +fragment DIGIT : [0-9] ; +fragment SIGN : [+-] ; +fragment EXP_CHAR : [eE] ; +fragment EXPONENT : EXP_CHAR SIGN? DIGIT+ ; +fragment DECIMAL : '.' DIGIT+ ; + +// All numbers are treated the same. No int/dec divide. +NUMBER : ( DIGIT+ DECIMAL? | DECIMAL ) EXPONENT? ; + +ID : [A-Za-z] [0-9A-Za-z_]* ; + +WS : [ \t\r\n\u000C]+ -> skip ; + +// Parser rules: + +/** + * All statements parseable from the input. Forces consumption of EOF token. + */ +allStatements : statements EOF ; + +statements : statement+ ; + +statement + : ( block + | ifStatement + | whileStatement + | doStatement + | forStatement + | simpleForStatement + | breakStatement + | continueStatement + | returnStatement + | switchStatement + | expressionStatement + | emptyStatement + ) SEMI_COLON? + ; + +block : '{' statements '}' ; + +ifStatement : IF '(' condition=expression ')' trueBranch=statement ( ELSE falseBranch=statement )? ; + +whileStatement : WHILE '(' condition=expression ')' body=statement ; + +doStatement : DO body=statement WHILE '(' condition=expression ')' ; + +// C-Style for loop +forStatement + : FOR '(' init=expression ';' condition=expression ';' update=expression ')' body=statement ; + +// Range for loop +simpleForStatement + : FOR '(' counter=ID ASSIGN first=expression ',' last=expression ')' body=statement ; + +breakStatement : BREAK ; + +continueStatement : CONTINUE ; + +returnStatement : RETURN value=expression ; + +switchStatement : SWITCH '(' target=expression ')' '{' (labels+=switchLabel ':' bodies+=statements )+ '}' ; + +switchLabel + : CASE constant=constantExpression # Case + | DEFAULT # Default + ; + +expressionStatement : expression ; + +emptyStatement: SEMI_COLON ; + +expression : assignmentExpression ; + +assignmentExpression + : conditionalExpression + | assignment + ; + +assignment + : target=ID assignmentOperator source=expression + ; + +assignmentOperator + : ASSIGN + | POWER_ASSIGN + | TIMES_ASSIGN + | DIVIDE_ASSIGN + | MODULO_ASSIGN + | PLUS_ASSIGN + | MINUS_ASSIGN + ; + +conditionalExpression + : conditionalOrExpression # CEFallthrough + | condition=conditionalOrExpression QUESTION_MARK + trueBranch=expression COLON falseBranch=conditionalExpression # TernaryExpr + ; + +conditionalOrExpression + : conditionalAndExpression # COFallthrough + | left=conditionalOrExpression OR_SC right=conditionalAndExpression # ConditionalOrExpr + ; + +conditionalAndExpression + : equalityExpression # CAFallthrough + | left=conditionalAndExpression AND_SC right=equalityExpression # ConditionalAndExpr + ; + +equalityExpression + : relationalExpression # EqFallthrough + | left=equalityExpression + op= + ( EQUAL + | NOT_EQUAL + | NEAR + ) right=relationalExpression # EqualityExpr + ; + +relationalExpression + : shiftExpression # ReFallthrough + | left=relationalExpression + op= + ( LESS_THAN + | GREATER_THAN + | LESS_THAN_OR_EQUAL + | GREATER_THAN_OR_EQUAL + ) right=shiftExpression # RelationalExpr + ; + +shiftExpression + : additiveExpression # ShFallthrough + | left=shiftExpression op=( LEFT_SHIFT | RIGHT_SHIFT ) right=additiveExpression # ShiftExpr + ; + +additiveExpression + : multiplicativeExpression # AdFallthrough + | left=additiveExpression op=( PLUS | MINUS ) right=multiplicativeExpression # AddExpr + ; + +multiplicativeExpression + : powerExpression # MuFallthrough + | left=multiplicativeExpression + op= + ( TIMES + | DIVIDE + | MODULO + ) right=powerExpression # MultiplicativeExpr + ; + +powerExpression + : unaryExpression # PwFallthrough + | left=powerExpression POWER right=unaryExpression # PowerExpr + ; + +unaryExpression + : op=( INCREMENT | DECREMENT ) target=ID # PreCrementExpr + | op=( PLUS | MINUS ) expr=unaryExpression # PlusMinusExpr + | postfixExpression # UaFallthrough + | COMPLEMENT expr=unaryExpression # ComplementExpr + | EXCLAMATION_MARK expr=unaryExpression # NotExpr + ; + +postfixExpression + : unprioritizedExpression # PoFallthrough + | target=ID op=( INCREMENT | DECREMENT) # PostCrementExpr + | expr=postfixExpression op=EXCLAMATION_MARK # PostfixExpr + ; + +unprioritizedExpression + : functionCall # FunctionCallExpr + | constantExpression # ConstantExpr + | source=ID # IdExpr + | '(' expression ')' # WrappedExpr + ; + +constantExpression : NUMBER ; + +functionCall : name=ID '(' (args+=expression ( ',' args+=expression )*)? ')' ; diff --git a/src/main/java/com/example/examplemod/Config.java b/src/main/java/com/example/examplemod/Config.java deleted file mode 100644 index 38dcbcd..0000000 --- a/src/main/java/com/example/examplemod/Config.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.example.examplemod; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; -import net.neoforged.fml.event.config.ModConfigEvent; -import net.neoforged.neoforge.common.ModConfigSpec; - -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -// An example config class. This is not required, but it's a good idea to have one to keep your config organized. -// Demonstrates how to use Forge's config APIs -@Mod.EventBusSubscriber(modid = ExampleMod.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) -public class Config -{ - private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder(); - - private static final ModConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER - .comment("Whether to log the dirt block on common setup") - .define("logDirtBlock", true); - - private static final ModConfigSpec.IntValue MAGIC_NUMBER = BUILDER - .comment("A magic number") - .defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE); - - public static final ModConfigSpec.ConfigValue MAGIC_NUMBER_INTRODUCTION = BUILDER - .comment("What you want the introduction message to be for the magic number") - .define("magicNumberIntroduction", "The magic number is... "); - - // a list of strings that are treated as resource locations for items - private static final ModConfigSpec.ConfigValue> ITEM_STRINGS = BUILDER - .comment("A list of items to log on common setup.") - .defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName); - - static final ModConfigSpec SPEC = BUILDER.build(); - - public static boolean logDirtBlock; - public static int magicNumber; - public static String magicNumberIntroduction; - public static Set items; - - private static boolean validateItemName(final Object obj) - { - return obj instanceof String itemName && BuiltInRegistries.ITEM.containsKey(new ResourceLocation(itemName)); - } - - @SubscribeEvent - static void onLoad(final ModConfigEvent event) - { - logDirtBlock = LOG_DIRT_BLOCK.get(); - magicNumber = MAGIC_NUMBER.get(); - magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get(); - - // convert the list of strings into a set of items - items = ITEM_STRINGS.get().stream() - .map(itemName -> BuiltInRegistries.ITEM.get(new ResourceLocation(itemName))) - .collect(Collectors.toSet()); - } -} diff --git a/src/main/java/com/example/examplemod/ExampleMod.java b/src/main/java/com/example/examplemod/ExampleMod.java deleted file mode 100644 index 4f50275..0000000 --- a/src/main/java/com/example/examplemod/ExampleMod.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.example.examplemod; - -import com.mojang.logging.LogUtils; -import net.minecraft.client.Minecraft; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.core.registries.Registries; -import net.minecraft.world.food.FoodProperties; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.CreativeModeTabs; -import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.material.MapColor; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.bus.api.IEventBus; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.ModLoadingContext; -import net.neoforged.fml.common.Mod; -import net.neoforged.fml.config.ModConfig; -import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; -import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; -import net.neoforged.neoforge.common.NeoForge; -import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; -import net.neoforged.neoforge.event.server.ServerStartingEvent; -import net.neoforged.neoforge.registries.DeferredBlock; -import net.neoforged.neoforge.registries.DeferredHolder; -import net.neoforged.neoforge.registries.DeferredItem; -import net.neoforged.neoforge.registries.DeferredRegister; -import org.slf4j.Logger; - -// The value here should match an entry in the META-INF/mods.toml file -@Mod(ExampleMod.MODID) -public class ExampleMod -{ - // Define mod id in a common place for everything to reference - public static final String MODID = "examplemod"; - // Directly reference a slf4j logger - private static final Logger LOGGER = LogUtils.getLogger(); - // Create a Deferred Register to hold Blocks which will all be registered under the "examplemod" namespace - public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(MODID); - // Create a Deferred Register to hold Items which will all be registered under the "examplemod" namespace - public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MODID); - // Create a Deferred Register to hold CreativeModeTabs which will all be registered under the "examplemod" namespace - public static final DeferredRegister CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID); - - // Creates a new Block with the id "examplemod:example_block", combining the namespace and path - public static final DeferredBlock EXAMPLE_BLOCK = BLOCKS.registerSimpleBlock("example_block", BlockBehaviour.Properties.of().mapColor(MapColor.STONE)); - // Creates a new BlockItem with the id "examplemod:example_block", combining the namespace and path - public static final DeferredItem EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem("example_block", EXAMPLE_BLOCK); - - // Creates a new food item with the id "examplemod:example_id", nutrition 1 and saturation 2 - public static final DeferredItem EXAMPLE_ITEM = ITEMS.registerSimpleItem("example_item", new Item.Properties().food(new FoodProperties.Builder() - .alwaysEat().nutrition(1).saturationMod(2f).build())); - - // Creates a creative tab with the id "examplemod:example_tab" for the example item, that is placed after the combat tab - public static final DeferredHolder EXAMPLE_TAB = CREATIVE_MODE_TABS.register("example_tab", () -> CreativeModeTab.builder() - .withTabsBefore(CreativeModeTabs.COMBAT) - .icon(() -> EXAMPLE_ITEM.get().getDefaultInstance()) - .displayItems((parameters, output) -> { - output.accept(EXAMPLE_ITEM.get()); // Add the example item to the tab. For your own tabs, this method is preferred over the event - }).build()); - - // The constructor for the mod class is the first code that is run when your mod is loaded. - // FML will recognize some parameter types like IEventBus or ModContainer and pass them in automatically. - public ExampleMod(IEventBus modEventBus) - { - // Register the commonSetup method for modloading - modEventBus.addListener(this::commonSetup); - - // Register the Deferred Register to the mod event bus so blocks get registered - BLOCKS.register(modEventBus); - // Register the Deferred Register to the mod event bus so items get registered - ITEMS.register(modEventBus); - // Register the Deferred Register to the mod event bus so tabs get registered - CREATIVE_MODE_TABS.register(modEventBus); - - // Register ourselves for server and other game events we are interested in - NeoForge.EVENT_BUS.register(this); - - // Register the item to a creative tab - modEventBus.addListener(this::addCreative); - - // Register our mod's ModConfigSpec so that FML can create and load the config file for us - ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC); - } - - private void commonSetup(final FMLCommonSetupEvent event) - { - // Some common setup code - LOGGER.info("HELLO FROM COMMON SETUP"); - - if (Config.logDirtBlock) - LOGGER.info("DIRT BLOCK >> {}", BuiltInRegistries.BLOCK.getKey(Blocks.DIRT)); - - LOGGER.info(Config.magicNumberIntroduction + Config.magicNumber); - - Config.items.forEach((item) -> LOGGER.info("ITEM >> {}", item.toString())); - } - - // Add the example block item to the building blocks tab - private void addCreative(BuildCreativeModeTabContentsEvent event) - { - if (event.getTabKey() == CreativeModeTabs.BUILDING_BLOCKS) - event.accept(EXAMPLE_BLOCK_ITEM); - } - - // You can use SubscribeEvent and let the Event Bus discover methods to call - @SubscribeEvent - public void onServerStarting(ServerStartingEvent event) - { - // Do something when the server starts - LOGGER.info("HELLO from server starting"); - } - - // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent - @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) - public static class ClientModEvents - { - @SubscribeEvent - public static void onClientSetup(FMLClientSetupEvent event) - { - // Some client setup code - LOGGER.info("HELLO FROM CLIENT SETUP"); - LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName()); - } - } -} diff --git a/src/main/java/com/sk89q/jnbt/ByteArrayTag.java b/src/main/java/com/sk89q/jnbt/ByteArrayTag.java new file mode 100644 index 0000000..78a9d75 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/ByteArrayTag.java @@ -0,0 +1,59 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import java.util.Locale; + +/** + * The {@code TAG_Byte_Array} tag. + */ +public final class ByteArrayTag extends Tag { + + private final byte[] value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public ByteArrayTag(byte[] value) { + super(); + this.value = value; + } + + @Override + public byte[] getValue() { + return value; + } + + @Override + public String toString() { + StringBuilder hex = new StringBuilder(); + for (byte b : value) { + String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ROOT); + if (hexDigits.length() == 1) { + hex.append("0"); + } + hex.append(hexDigits).append(" "); + } + return "TAG_Byte_Array(" + hex + ")"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/ByteTag.java b/src/main/java/com/sk89q/jnbt/ByteTag.java new file mode 100644 index 0000000..e7fe1cc --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/ByteTag.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +/** + * The {@code TAG_Byte} tag. + */ +public final class ByteTag extends Tag { + + private final byte value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public ByteTag(byte value) { + super(); + this.value = value; + } + + @Override + public Byte getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Byte(" + value + ")"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/CompoundTag.java b/src/main/java/com/sk89q/jnbt/CompoundTag.java new file mode 100644 index 0000000..e3c75d2 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/CompoundTag.java @@ -0,0 +1,438 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * The {@code TAG_Compound} tag. + */ +public final class CompoundTag extends Tag { + + private final Map value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public CompoundTag(Map value) { + super(); + this.value = Collections.unmodifiableMap(value); + } + + /** + * Returns whether this compound tag contains the given key. + * + * @param key the given key + * @return true if the tag contains the given key + */ + public boolean containsKey(String key) { + return value.containsKey(key); + } + + @Override + public Map getValue() { + return value; + } + + /** + * Return a new compound tag with the given values. + * + * @param value the value + * @return the new compound tag + */ + public CompoundTag setValue(Map value) { + return new CompoundTag(value); + } + + /** + * Create a compound tag builder. + * + * @return the builder + */ + public CompoundTagBuilder createBuilder() { + return new CompoundTagBuilder(new HashMap<>(value)); + } + + /** + * Get a byte array named with the given key. + * + *

If the key does not exist or its value is not a byte array tag, + * then an empty byte array will be returned.

+ * + * @param key the key + * @return a byte array + */ + public byte[] getByteArray(String key) { + Tag tag = value.get(key); + if (tag instanceof ByteArrayTag) { + return ((ByteArrayTag) tag).getValue(); + } else { + return new byte[0]; + } + } + + /** + * Get a byte named with the given key. + * + *

If the key does not exist or its value is not a byte tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a byte + */ + public byte getByte(String key) { + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + } else { + return (byte) 0; + } + } + + /** + * Get a double named with the given key. + * + *

If the key does not exist or its value is not a double tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a double + */ + public double getDouble(String key) { + Tag tag = value.get(key); + if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a double named with the given key, even if it's another + * type of number. + * + *

If the key does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a double + */ + public double asDouble(String key) { + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue(); + + } else { + return 0; + } + } + + /** + * Get a float named with the given key. + * + *

If the key does not exist or its value is not a float tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a float + */ + public float getFloat(String key) { + Tag tag = value.get(key); + if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a {@code int[]} named with the given key. + * + *

If the key does not exist or its value is not an int array tag, + * then an empty array will be returned.

+ * + * @param key the key + * @return an int array + */ + public int[] getIntArray(String key) { + Tag tag = value.get(key); + if (tag instanceof IntArrayTag) { + return ((IntArrayTag) tag).getValue(); + } else { + return new int[0]; + } + } + + /** + * Get an int named with the given key. + * + *

If the key does not exist or its value is not an int tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return an int + */ + public int getInt(String key) { + Tag tag = value.get(key); + if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get an int named with the given key, even if it's another + * type of number. + * + *

If the key does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return an int + */ + public int asInt(String key) { + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue().intValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue().intValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue().intValue(); + + } else { + return 0; + } + } + + /** + * Get a list of tags named with the given key. + * + *

If the key does not exist or its value is not a list tag, + * then an empty list will be returned.

+ * + * @param key the key + * @return a list of tags + */ + public List getList(String key) { + Tag tag = value.get(key); + if (tag instanceof ListTag) { + return ((ListTag) tag).getValue(); + } else { + return Collections.emptyList(); + } + } + + /** + * Get a {@code TagList} named with the given key. + * + *

If the key does not exist or its value is not a list tag, + * then an empty tag list will be returned.

+ * + * @param key the key + * @return a tag list instance + */ + public ListTag getListTag(String key) { + Tag tag = value.get(key); + if (tag instanceof ListTag) { + return (ListTag) tag; + } else { + return new ListTag(StringTag.class, Collections.emptyList()); + } + } + + /** + * Get a list of tags named with the given key. + * + *

If the key does not exist or its value is not a list tag, + * then an empty list will be returned. If the given key references + * a list but the list of of a different type, then an empty + * list will also be returned.

+ * + * @param key the key + * @param listType the class of the contained type + * @param the type of list + * @return a list of tags + */ + @SuppressWarnings("unchecked") + public List getList(String key, Class listType) { + Tag tag = value.get(key); + if (tag instanceof ListTag) { + ListTag listTag = (ListTag) tag; + if (listTag.getType().equals(listType)) { + return (List) listTag.getValue(); + } else { + return Collections.emptyList(); + } + } else { + return Collections.emptyList(); + } + } + + /** + * Get a {@code long[]} named with the given key. + * + *

If the key does not exist or its value is not an long array tag, + * then an empty array will be returned.

+ * + * @param key the key + * @return an int array + */ + public long[] getLongArray(String key) { + Tag tag = value.get(key); + if (tag instanceof LongArrayTag) { + return ((LongArrayTag) tag).getValue(); + } else { + return new long[0]; + } + } + + /** + * Get a long named with the given key. + * + *

If the key does not exist or its value is not a long tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a long + */ + public long getLong(String key) { + Tag tag = value.get(key); + if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + } else { + return 0L; + } + } + + /** + * Get a long named with the given key, even if it's another + * type of number. + * + *

If the key does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a long + */ + public long asLong(String key) { + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue().longValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue().longValue(); + + } else { + return 0L; + } + } + + /** + * Get a short named with the given key. + * + *

If the key does not exist or its value is not a short tag, + * then {@code 0} will be returned.

+ * + * @param key the key + * @return a short + */ + public short getShort(String key) { + Tag tag = value.get(key); + if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a string named with the given key. + * + *

If the key does not exist or its value is not a string tag, + * then {@code ""} will be returned.

+ * + * @param key the key + * @return a string + */ + public String getString(String key) { + Tag tag = value.get(key); + if (tag instanceof StringTag) { + return ((StringTag) tag).getValue(); + } else { + return ""; + } + } + + @Override + public String toString() { + StringBuilder bldr = new StringBuilder(); + bldr.append("TAG_Compound").append(": ").append(value.size()).append(" entries\r\n{\r\n"); + for (Map.Entry entry : value.entrySet()) { + bldr.append(" ").append(entry.getValue().toString().replaceAll("\r\n", "\r\n ")).append("\r\n"); + } + bldr.append("}"); + return bldr.toString(); + } + +} diff --git a/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java b/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java new file mode 100644 index 0000000..7267a72 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java @@ -0,0 +1,228 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helps create compound tags. + */ +public class CompoundTagBuilder { + + private final Map entries; + + /** + * Create a new instance. + */ + CompoundTagBuilder() { + this.entries = new HashMap<>(); + } + + /** + * Create a new instance and use the given map (which will be modified). + * + * @param value the value + */ + CompoundTagBuilder(Map value) { + checkNotNull(value); + this.entries = value; + } + + /** + * Put the given key and tag into the compound tag. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder put(String key, Tag value) { + checkNotNull(key); + checkNotNull(value); + entries.put(key, value); + return this; + } + + /** + * Put the given key and value into the compound tag as a + * {@code ByteArrayTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putByteArray(String key, byte[] value) { + return put(key, new ByteArrayTag(value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code ByteTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putByte(String key, byte value) { + return put(key, new ByteTag(value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code DoubleTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putDouble(String key, double value) { + return put(key, new DoubleTag(value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code FloatTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putFloat(String key, float value) { + return put(key, new FloatTag(value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code IntArrayTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putIntArray(String key, int[] value) { + return put(key, new IntArrayTag(value)); + } + + /** + * Put the given key and value into the compound tag as an {@code IntTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putInt(String key, int value) { + return put(key, new IntTag(value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code LongArrayTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putLongArray(String key, long[] value) { + return put(key, new LongArrayTag(value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code LongTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putLong(String key, long value) { + return put(key, new LongTag(value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code ShortTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putShort(String key, short value) { + return put(key, new ShortTag(value)); + } + + /** + * Put the given key and value into the compound tag as a + * {@code StringTag}. + * + * @param key they key + * @param value the value + * @return this object + */ + public CompoundTagBuilder putString(String key, String value) { + return put(key, new StringTag(value)); + } + + /** + * Remove the given key from the compound tag. Does nothing if the key doesn't exist. + * + * @param key the key + * @return this object + */ + public CompoundTagBuilder remove(String key) { + checkNotNull(key); + entries.remove(key); + return this; + } + + /** + * Put all the entries from the given map into this map. + * + * @param value the map of tags + * @return this object + */ + public CompoundTagBuilder putAll(Map value) { + checkNotNull(value); + for (Map.Entry entry : value.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + return this; + } + + /** + * Build an unnamed compound tag with this builder's entries. + * + * @return the new compound tag + */ + public CompoundTag build() { + return new CompoundTag(new HashMap<>(entries)); + } + + /** + * Create a new builder instance. + * + * @return a new builder + */ + public static CompoundTagBuilder create() { + return new CompoundTagBuilder(); + } + +} diff --git a/src/main/java/com/sk89q/jnbt/DoubleTag.java b/src/main/java/com/sk89q/jnbt/DoubleTag.java new file mode 100644 index 0000000..b579308 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/DoubleTag.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +/** + * The {@code TAG_Double} tag. + */ +public final class DoubleTag extends Tag { + + private final double value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public DoubleTag(double value) { + super(); + this.value = value; + } + + @Override + public Double getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Double(" + value + ")"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/EndTag.java b/src/main/java/com/sk89q/jnbt/EndTag.java new file mode 100644 index 0000000..c6fc635 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/EndTag.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +/** + * The {@code TAG_End} tag. + */ +public final class EndTag extends Tag { + + @Override + public Object getValue() { + return null; + } + + @Override + public String toString() { + return "TAG_End"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/FloatTag.java b/src/main/java/com/sk89q/jnbt/FloatTag.java new file mode 100644 index 0000000..e1281ea --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/FloatTag.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +/** + * The {@code TAG_Float} tag. + */ +public final class FloatTag extends Tag { + + private final float value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public FloatTag(float value) { + super(); + this.value = value; + } + + @Override + public Float getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Float(" + value + ")"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/IntArrayTag.java b/src/main/java/com/sk89q/jnbt/IntArrayTag.java new file mode 100644 index 0000000..39c6217 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/IntArrayTag.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import java.util.Locale; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The {@code TAG_Int_Array} tag. + */ +public final class IntArrayTag extends Tag { + + private final int[] value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public IntArrayTag(int[] value) { + super(); + checkNotNull(value); + this.value = value; + } + + @Override + public int[] getValue() { + return value; + } + + @Override + public String toString() { + StringBuilder hex = new StringBuilder(); + for (int b : value) { + String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ROOT); + if (hexDigits.length() == 1) { + hex.append("0"); + } + hex.append(hexDigits).append(" "); + } + return "TAG_Int_Array(" + hex + ")"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/IntTag.java b/src/main/java/com/sk89q/jnbt/IntTag.java new file mode 100644 index 0000000..359cf85 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/IntTag.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +/** + * The {@code TAG_Int} tag. + */ +public final class IntTag extends Tag { + + private final int value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public IntTag(int value) { + super(); + this.value = value; + } + + @Override + public Integer getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Int(" + value + ")"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/ListTag.java b/src/main/java/com/sk89q/jnbt/ListTag.java new file mode 100644 index 0000000..35f6518 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/ListTag.java @@ -0,0 +1,429 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The {@code TAG_List} tag. + */ +public final class ListTag extends Tag { + + private final Class type; + private final List value; + + /** + * Creates the tag with an empty name. + * + * @param type the type of tag + * @param value the value of the tag + */ + public ListTag(Class type, List value) { + super(); + checkNotNull(value); + this.type = type; + this.value = Collections.unmodifiableList(value); + } + + /** + * Gets the type of item in this list. + * + * @return The type of item in this list. + */ + public Class getType() { + return type; + } + + @Override + public List getValue() { + return value; + } + + /** + * Create a new list tag with this tag's name and type. + * + * @param list the new list + * @return a new list tag + */ + public ListTag setValue(List list) { + return new ListTag(getType(), list); + } + + /** + * Get the tag if it exists at the given index. + * + * @param index the index + * @return the tag or null + */ + @Nullable + public Tag getIfExists(int index) { + if (index >= value.size()) { + return null; + } + return value.get(index); + } + + /** + * Get a byte array named with the given index. + * + *

If the index does not exist or its value is not a byte array tag, + * then an empty byte array will be returned.

+ * + * @param index the index + * @return a byte array + */ + public byte[] getByteArray(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ByteArrayTag) { + return ((ByteArrayTag) tag).getValue(); + } else { + return new byte[0]; + } + } + + /** + * Get a byte named with the given index. + * + *

If the index does not exist or its value is not a byte tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a byte + */ + public byte getByte(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + } else { + return (byte) 0; + } + } + + /** + * Get a double named with the given index. + * + *

If the index does not exist or its value is not a double tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a double + */ + public double getDouble(int index) { + Tag tag = getIfExists(index); + if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a double named with the given index, even if it's another + * type of number. + * + *

If the index does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a double + */ + public double asDouble(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue(); + + } else { + return 0; + } + } + + /** + * Get a float named with the given index. + * + *

If the index does not exist or its value is not a float tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a float + */ + public float getFloat(int index) { + Tag tag = getIfExists(index); + if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a {@code int[]} named with the given index. + * + *

If the index does not exist or its value is not an int array tag, + * then an empty array will be returned.

+ * + * @param index the index + * @return an int array + */ + public int[] getIntArray(int index) { + Tag tag = getIfExists(index); + if (tag instanceof IntArrayTag) { + return ((IntArrayTag) tag).getValue(); + } else { + return new int[0]; + } + } + + /** + * Get an int named with the given index. + * + *

If the index does not exist or its value is not an int tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return an int + */ + public int getInt(int index) { + Tag tag = getIfExists(index); + if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get an int named with the given index, even if it's another + * type of number. + * + *

If the index does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return an int + */ + public int asInt(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue().intValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue().intValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue().intValue(); + + } else { + return 0; + } + } + + /** + * Get a list of tags named with the given index. + * + *

If the index does not exist or its value is not a list tag, + * then an empty list will be returned.

+ * + * @param index the index + * @return a list of tags + */ + public List getList(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ListTag) { + return ((ListTag) tag).getValue(); + } else { + return Collections.emptyList(); + } + } + + /** + * Get a {@code TagList} named with the given index. + * + *

If the index does not exist or its value is not a list tag, + * then an empty tag list will be returned.

+ * + * @param index the index + * @return a tag list instance + */ + public ListTag getListTag(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ListTag) { + return (ListTag) tag; + } else { + return new ListTag(StringTag.class, Collections.emptyList()); + } + } + + /** + * Get a list of tags named with the given index. + * + *

If the index does not exist or its value is not a list tag, + * then an empty list will be returned. If the given index references + * a list but the list of of a different type, then an empty + * list will also be returned.

+ * + * @param index the index + * @param listType the class of the contained type + * @param the NBT type + * @return a list of tags + */ + @SuppressWarnings("unchecked") + public List getList(int index, Class listType) { + Tag tag = getIfExists(index); + if (tag instanceof ListTag) { + ListTag listTag = (ListTag) tag; + if (listTag.getType().equals(listType)) { + return (List) listTag.getValue(); + } else { + return Collections.emptyList(); + } + } else { + return Collections.emptyList(); + } + } + + /** + * Get a long named with the given index. + * + *

If the index does not exist or its value is not a long tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a long + */ + public long getLong(int index) { + Tag tag = getIfExists(index); + if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + } else { + return 0L; + } + } + + /** + * Get a long named with the given index, even if it's another + * type of number. + * + *

If the index does not exist or its value is not a number, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a long + */ + public long asLong(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue().longValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue().longValue(); + + } else { + return 0; + } + } + + /** + * Get a short named with the given index. + * + *

If the index does not exist or its value is not a short tag, + * then {@code 0} will be returned.

+ * + * @param index the index + * @return a short + */ + public short getShort(int index) { + Tag tag = getIfExists(index); + if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + } else { + return 0; + } + } + + /** + * Get a string named with the given index. + * + *

If the index does not exist or its value is not a string tag, + * then {@code ""} will be returned.

+ * + * @param index the index + * @return a string + */ + public String getString(int index) { + Tag tag = getIfExists(index); + if (tag instanceof StringTag) { + return ((StringTag) tag).getValue(); + } else { + return ""; + } + } + + @Override + public String toString() { + StringBuilder bldr = new StringBuilder(); + bldr.append("TAG_List").append(": ").append(value.size()).append(" entries of type ").append(NBTUtils.getTypeName(type)).append("\r\n{\r\n"); + for (Tag t : value) { + bldr.append(" ").append(t.toString().replaceAll("\r\n", "\r\n ")).append("\r\n"); + } + bldr.append("}"); + return bldr.toString(); + } + +} diff --git a/src/main/java/com/sk89q/jnbt/ListTagBuilder.java b/src/main/java/com/sk89q/jnbt/ListTagBuilder.java new file mode 100644 index 0000000..b98c667 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/ListTagBuilder.java @@ -0,0 +1,119 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helps create list tags. + */ +public class ListTagBuilder { + + private final Class type; + private final List entries; + + /** + * Create a new instance. + * + * @param type of tag contained in this list + */ + ListTagBuilder(Class type) { + checkNotNull(type); + this.type = type; + this.entries = new ArrayList<>(); + } + + /** + * Add the given tag. + * + * @param value the tag + * @return this object + */ + public ListTagBuilder add(Tag value) { + checkNotNull(value); + if (!type.isInstance(value)) { + throw new IllegalArgumentException(value.getClass().getCanonicalName() + " is not of expected type " + type.getCanonicalName()); + } + entries.add(value); + return this; + } + + /** + * Add all the tags in the given list. + * + * @param value a list of tags + * @return this object + */ + public ListTagBuilder addAll(Collection value) { + checkNotNull(value); + for (Tag v : value) { + add(v); + } + return this; + } + + /** + * Build an unnamed list tag with this builder's entries. + * + * @return the new list tag + */ + public ListTag build() { + return new ListTag(type, new ArrayList<>(entries)); + } + + /** + * Create a new builder instance. + * + * @return a new builder + */ + public static ListTagBuilder create(Class type) { + return new ListTagBuilder(type); + } + + /** + * Create a new builder instance. + * + * @return a new builder + */ + public static ListTagBuilder createWith(Tag... entries) { + checkNotNull(entries); + + if (entries.length == 0) { + throw new IllegalArgumentException("This method needs an array of at least one entry"); + } + + Class type = entries[0].getClass(); + for (int i = 1; i < entries.length; i++) { + if (!type.isInstance(entries[i])) { + throw new IllegalArgumentException("An array of different tag types was provided"); + } + } + + ListTagBuilder builder = new ListTagBuilder(type); + builder.addAll(Arrays.asList(entries)); + return builder; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/LongArrayTag.java b/src/main/java/com/sk89q/jnbt/LongArrayTag.java new file mode 100644 index 0000000..c2e9688 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/LongArrayTag.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import java.util.Locale; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The {@code TAG_Long_Array} tag. + */ +public class LongArrayTag extends Tag { + + private final long[] value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public LongArrayTag(long[] value) { + super(); + checkNotNull(value); + this.value = value; + } + + @Override + public long[] getValue() { + return value; + } + + @Override + public String toString() { + StringBuilder hex = new StringBuilder(); + for (long b : value) { + String hexDigits = Long.toHexString(b).toUpperCase(Locale.ROOT); + if (hexDigits.length() == 1) { + hex.append("0"); + } + hex.append(hexDigits).append(" "); + } + return "TAG_Long_Array(" + hex + ")"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/LongTag.java b/src/main/java/com/sk89q/jnbt/LongTag.java new file mode 100644 index 0000000..8f89452 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/LongTag.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +/** + * The {@code TAG_Long} tag. + */ +public final class LongTag extends Tag { + + private final long value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public LongTag(long value) { + super(); + this.value = value; + } + + @Override + public Long getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Long(" + value + ")"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/NBTConstants.java b/src/main/java/com/sk89q/jnbt/NBTConstants.java new file mode 100644 index 0000000..db6689c --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/NBTConstants.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import java.nio.charset.Charset; + +/** + * A class which holds constant values. + */ +public final class NBTConstants { + + public static final Charset CHARSET = Charset.forName("UTF-8"); + + public static final int TYPE_END = 0; + public static final int TYPE_BYTE = 1; + public static final int TYPE_SHORT = 2; + public static final int TYPE_INT = 3; + public static final int TYPE_LONG = 4; + public static final int TYPE_FLOAT = 5; + public static final int TYPE_DOUBLE = 6; + public static final int TYPE_BYTE_ARRAY = 7; + public static final int TYPE_STRING = 8; + public static final int TYPE_LIST = 9; + public static final int TYPE_COMPOUND = 10; + public static final int TYPE_INT_ARRAY = 11; + public static final int TYPE_LONG_ARRAY = 12; + + /** + * Default private constructor. + */ + private NBTConstants() { + + } + + /** + * Convert a type ID to its corresponding {@link Tag} class. + * + * @param id type ID + * @return tag class + * @throws IllegalArgumentException thrown if the tag ID is not valid + */ + public static Class getClassFromType(int id) { + switch (id) { + case TYPE_END: + return EndTag.class; + case TYPE_BYTE: + return ByteTag.class; + case TYPE_SHORT: + return ShortTag.class; + case TYPE_INT: + return IntTag.class; + case TYPE_LONG: + return LongTag.class; + case TYPE_FLOAT: + return FloatTag.class; + case TYPE_DOUBLE: + return DoubleTag.class; + case TYPE_BYTE_ARRAY: + return ByteArrayTag.class; + case TYPE_STRING: + return StringTag.class; + case TYPE_LIST: + return ListTag.class; + case TYPE_COMPOUND: + return CompoundTag.class; + case TYPE_INT_ARRAY: + return IntArrayTag.class; + case TYPE_LONG_ARRAY: + return LongArrayTag.class; + default: + throw new IllegalArgumentException("Unknown tag type ID of " + id); + } + } + +} diff --git a/src/main/java/com/sk89q/jnbt/NBTInputStream.java b/src/main/java/com/sk89q/jnbt/NBTInputStream.java new file mode 100644 index 0000000..35a0bb6 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/NBTInputStream.java @@ -0,0 +1,179 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import java.io.Closeable; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This class reads NBT, or Named Binary Tag + * streams, and produces an object graph of subclasses of the {@code Tag} + * object. + * + *

+ * The NBT format was created by Markus Persson, and the specification may be + * found at + * https://minecraft.gamepedia.com/NBT_format. + *

+ */ +public final class NBTInputStream implements Closeable { + + private final DataInputStream is; + + /** + * Creates a new {@code NBTInputStream}, which will source its data + * from the specified input stream. + * + * @param is the input stream + */ + public NBTInputStream(InputStream is) { + this.is = new DataInputStream(is); + } + + /** + * Reads an NBT tag from the stream. + * + * @return The tag that was read. + * @throws IOException if an I/O error occurs. + */ + public NamedTag readNamedTag() throws IOException { + return readNamedTag(0); + } + + /** + * Reads an NBT from the stream. + * + * @param depth the depth of this tag + * @return The tag that was read. + * @throws IOException if an I/O error occurs. + */ + private NamedTag readNamedTag(int depth) throws IOException { + int type = is.readByte() & 0xFF; + + String name; + if (type != NBTConstants.TYPE_END) { + int nameLength = is.readShort() & 0xFFFF; + byte[] nameBytes = new byte[nameLength]; + is.readFully(nameBytes); + name = new String(nameBytes, NBTConstants.CHARSET); + } else { + name = ""; + } + + return new NamedTag(name, readTagPayload(type, depth)); + } + + /** + * Reads the payload of a tag given the type. + * + * @param type the type + * @param depth the depth + * @return the tag + * @throws IOException if an I/O error occurs. + */ + private Tag readTagPayload(int type, int depth) throws IOException { + switch (type) { + case NBTConstants.TYPE_END: + if (depth == 0) { + throw new IOException( + "TAG_End found without a TAG_Compound/TAG_List tag preceding it."); + } else { + return new EndTag(); + } + case NBTConstants.TYPE_BYTE: + return new ByteTag(is.readByte()); + case NBTConstants.TYPE_SHORT: + return new ShortTag(is.readShort()); + case NBTConstants.TYPE_INT: + return new IntTag(is.readInt()); + case NBTConstants.TYPE_LONG: + return new LongTag(is.readLong()); + case NBTConstants.TYPE_FLOAT: + return new FloatTag(is.readFloat()); + case NBTConstants.TYPE_DOUBLE: + return new DoubleTag(is.readDouble()); + case NBTConstants.TYPE_BYTE_ARRAY: + int length = is.readInt(); + byte[] bytes = new byte[length]; + is.readFully(bytes); + return new ByteArrayTag(bytes); + case NBTConstants.TYPE_STRING: + length = is.readShort(); + bytes = new byte[length]; + is.readFully(bytes); + return new StringTag(new String(bytes, NBTConstants.CHARSET)); + case NBTConstants.TYPE_LIST: + int childType = is.readByte(); + length = is.readInt(); + + List tagList = new ArrayList<>(); + for (int i = 0; i < length; ++i) { + Tag tag = readTagPayload(childType, depth + 1); + if (tag instanceof EndTag) { + throw new IOException("TAG_End not permitted in a list."); + } + tagList.add(tag); + } + + return new ListTag(NBTUtils.getTypeClass(childType), tagList); + case NBTConstants.TYPE_COMPOUND: + Map tagMap = new HashMap<>(); + while (true) { + NamedTag namedTag = readNamedTag(depth + 1); + Tag tag = namedTag.getTag(); + if (tag instanceof EndTag) { + break; + } else { + tagMap.put(namedTag.getName(), tag); + } + } + + return new CompoundTag(tagMap); + case NBTConstants.TYPE_INT_ARRAY: + length = is.readInt(); + int[] data = new int[length]; + for (int i = 0; i < length; i++) { + data[i] = is.readInt(); + } + return new IntArrayTag(data); + case NBTConstants.TYPE_LONG_ARRAY: + length = is.readInt(); + long[] longData = new long[length]; + for (int i = 0; i < length; i++) { + longData[i] = is.readLong(); + } + return new LongArrayTag(longData); + default: + throw new IOException("Invalid tag type: " + type + "."); + } + } + + @Override + public void close() throws IOException { + is.close(); + } + +} diff --git a/src/main/java/com/sk89q/jnbt/NBTOutputStream.java b/src/main/java/com/sk89q/jnbt/NBTOutputStream.java new file mode 100644 index 0000000..98ccb72 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/NBTOutputStream.java @@ -0,0 +1,307 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import java.io.Closeable; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * This class writes NBT, or Named Binary Tag + * {@code Tag} objects to an underlying {@code OutputStream}. + * + *

+ * The NBT format was created by Markus Persson, and the specification may be + * found at + * https://minecraft.gamepedia.com/NBT_format. + *

+ */ +public final class NBTOutputStream implements Closeable { + + /** + * The output stream. + */ + private final DataOutputStream os; + + /** + * Creates a new {@code NBTOutputStream}, which will write data to the + * specified underlying output stream. + * + * @param os + * The output stream. + * @throws IOException + * if an I/O error occurs. + */ + public NBTOutputStream(OutputStream os) throws IOException { + this.os = new DataOutputStream(os); + } + + /** + * Writes a tag. + * + * @param tag + * The tag to write. + * @throws IOException + * if an I/O error occurs. + */ + public void writeNamedTag(String name, Tag tag) throws IOException { + checkNotNull(name); + checkNotNull(tag); + + int type = NBTUtils.getTypeCode(tag.getClass()); + byte[] nameBytes = name.getBytes(NBTConstants.CHARSET); + + os.writeByte(type); + os.writeShort(nameBytes.length); + os.write(nameBytes); + + if (type == NBTConstants.TYPE_END) { + throw new IOException("Named TAG_End not permitted."); + } + + writeTagPayload(tag); + } + + /** + * Writes tag payload. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeTagPayload(Tag tag) throws IOException { + int type = NBTUtils.getTypeCode(tag.getClass()); + switch (type) { + case NBTConstants.TYPE_END: + writeEndTagPayload((EndTag) tag); + break; + case NBTConstants.TYPE_BYTE: + writeByteTagPayload((ByteTag) tag); + break; + case NBTConstants.TYPE_SHORT: + writeShortTagPayload((ShortTag) tag); + break; + case NBTConstants.TYPE_INT: + writeIntTagPayload((IntTag) tag); + break; + case NBTConstants.TYPE_LONG: + writeLongTagPayload((LongTag) tag); + break; + case NBTConstants.TYPE_FLOAT: + writeFloatTagPayload((FloatTag) tag); + break; + case NBTConstants.TYPE_DOUBLE: + writeDoubleTagPayload((DoubleTag) tag); + break; + case NBTConstants.TYPE_BYTE_ARRAY: + writeByteArrayTagPayload((ByteArrayTag) tag); + break; + case NBTConstants.TYPE_STRING: + writeStringTagPayload((StringTag) tag); + break; + case NBTConstants.TYPE_LIST: + writeListTagPayload((ListTag) tag); + break; + case NBTConstants.TYPE_COMPOUND: + writeCompoundTagPayload((CompoundTag) tag); + break; + case NBTConstants.TYPE_INT_ARRAY: + writeIntArrayTagPayload((IntArrayTag) tag); + break; + case NBTConstants.TYPE_LONG_ARRAY: + writeLongArrayTagPayload((LongArrayTag) tag); + break; + default: + throw new IOException("Invalid tag type: " + type + "."); + } + } + + /** + * Writes a {@code TAG_Byte} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeByteTagPayload(ByteTag tag) throws IOException { + os.writeByte(tag.getValue()); + } + + /** + * Writes a {@code TAG_Byte_Array} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeByteArrayTagPayload(ByteArrayTag tag) throws IOException { + byte[] bytes = tag.getValue(); + os.writeInt(bytes.length); + os.write(bytes); + } + + /** + * Writes a {@code TAG_Compound} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeCompoundTagPayload(CompoundTag tag) throws IOException { + for (Map.Entry entry : tag.getValue().entrySet()) { + writeNamedTag(entry.getKey(), entry.getValue()); + } + os.writeByte((byte) 0); // end tag - better way? + } + + /** + * Writes a {@code TAG_List} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeListTagPayload(ListTag tag) throws IOException { + Class clazz = tag.getType(); + List tags = tag.getValue(); + int size = tags.size(); + + os.writeByte(NBTUtils.getTypeCode(clazz)); + os.writeInt(size); + for (Tag tag1 : tags) { + writeTagPayload(tag1); + } + } + + /** + * Writes a {@code TAG_String} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeStringTagPayload(StringTag tag) throws IOException { + byte[] bytes = tag.getValue().getBytes(NBTConstants.CHARSET); + os.writeShort(bytes.length); + os.write(bytes); + } + + /** + * Writes a {@code TAG_Double} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeDoubleTagPayload(DoubleTag tag) throws IOException { + os.writeDouble(tag.getValue()); + } + + /** + * Writes a {@code TAG_Float} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeFloatTagPayload(FloatTag tag) throws IOException { + os.writeFloat(tag.getValue()); + } + + /** + * Writes a {@code TAG_Long} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeLongTagPayload(LongTag tag) throws IOException { + os.writeLong(tag.getValue()); + } + + /** + * Writes a {@code TAG_Int} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeIntTagPayload(IntTag tag) throws IOException { + os.writeInt(tag.getValue()); + } + + /** + * Writes a {@code TAG_Short} tag. + * + * @param tag + * The tag. + * @throws IOException + * if an I/O error occurs. + */ + private void writeShortTagPayload(ShortTag tag) throws IOException { + os.writeShort(tag.getValue()); + } + + /** + * Writes a {@code TAG_Empty} tag. + * + * @param tag the tag + */ + private void writeEndTagPayload(EndTag tag) { + /* empty */ + } + + private void writeIntArrayTagPayload(IntArrayTag tag) throws IOException { + int[] data = tag.getValue(); + os.writeInt(data.length); + for (int aData : data) { + os.writeInt(aData); + } + } + + private void writeLongArrayTagPayload(LongArrayTag tag) throws IOException { + long[] data = tag.getValue(); + os.writeInt(data.length); + for (long aData : data) { + os.writeLong(aData); + } + } + + @Override + public void close() throws IOException { + os.close(); + } + +} diff --git a/src/main/java/com/sk89q/jnbt/NBTUtils.java b/src/main/java/com/sk89q/jnbt/NBTUtils.java new file mode 100644 index 0000000..c6e53e5 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -0,0 +1,195 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.world.storage.InvalidFormatException; + +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A class which contains NBT-related utility methods. + * + */ +public final class NBTUtils { + + /** + * Default private constructor. + */ + private NBTUtils() { + } + + /** + * Gets the type name of a tag. + * + * @param clazz the tag class + * @return The type name. + */ + public static String getTypeName(Class clazz) { + if (clazz.equals(ByteArrayTag.class)) { + return "TAG_Byte_Array"; + } else if (clazz.equals(ByteTag.class)) { + return "TAG_Byte"; + } else if (clazz.equals(CompoundTag.class)) { + return "TAG_Compound"; + } else if (clazz.equals(DoubleTag.class)) { + return "TAG_Double"; + } else if (clazz.equals(EndTag.class)) { + return "TAG_End"; + } else if (clazz.equals(FloatTag.class)) { + return "TAG_Float"; + } else if (clazz.equals(IntTag.class)) { + return "TAG_Int"; + } else if (clazz.equals(ListTag.class)) { + return "TAG_List"; + } else if (clazz.equals(LongTag.class)) { + return "TAG_Long"; + } else if (clazz.equals(ShortTag.class)) { + return "TAG_Short"; + } else if (clazz.equals(StringTag.class)) { + return "TAG_String"; + } else if (clazz.equals(IntArrayTag.class)) { + return "TAG_Int_Array"; + } else if (clazz.equals(LongArrayTag.class)) { + return "TAG_Long_Array"; + } else { + throw new IllegalArgumentException("Invalid tag classs (" + + clazz.getName() + ")."); + } + } + + /** + * Gets the type code of a tag class. + * + * @param clazz the tag class + * @return The type code. + * @throws IllegalArgumentException if the tag class is invalid. + */ + public static int getTypeCode(Class clazz) { + if (clazz.equals(ByteArrayTag.class)) { + return NBTConstants.TYPE_BYTE_ARRAY; + } else if (clazz.equals(ByteTag.class)) { + return NBTConstants.TYPE_BYTE; + } else if (clazz.equals(CompoundTag.class)) { + return NBTConstants.TYPE_COMPOUND; + } else if (clazz.equals(DoubleTag.class)) { + return NBTConstants.TYPE_DOUBLE; + } else if (clazz.equals(EndTag.class)) { + return NBTConstants.TYPE_END; + } else if (clazz.equals(FloatTag.class)) { + return NBTConstants.TYPE_FLOAT; + } else if (clazz.equals(IntTag.class)) { + return NBTConstants.TYPE_INT; + } else if (clazz.equals(ListTag.class)) { + return NBTConstants.TYPE_LIST; + } else if (clazz.equals(LongTag.class)) { + return NBTConstants.TYPE_LONG; + } else if (clazz.equals(ShortTag.class)) { + return NBTConstants.TYPE_SHORT; + } else if (clazz.equals(StringTag.class)) { + return NBTConstants.TYPE_STRING; + } else if (clazz.equals(IntArrayTag.class)) { + return NBTConstants.TYPE_INT_ARRAY; + } else if (clazz.equals(LongArrayTag.class)) { + return NBTConstants.TYPE_LONG_ARRAY; + } else { + throw new IllegalArgumentException("Invalid tag classs (" + + clazz.getName() + ")."); + } + } + + /** + * Gets the class of a type of tag. + * + * @param type the type + * @return The class. + * @throws IllegalArgumentException if the tag type is invalid. + */ + public static Class getTypeClass(int type) { + switch (type) { + case NBTConstants.TYPE_END: + return EndTag.class; + case NBTConstants.TYPE_BYTE: + return ByteTag.class; + case NBTConstants.TYPE_SHORT: + return ShortTag.class; + case NBTConstants.TYPE_INT: + return IntTag.class; + case NBTConstants.TYPE_LONG: + return LongTag.class; + case NBTConstants.TYPE_FLOAT: + return FloatTag.class; + case NBTConstants.TYPE_DOUBLE: + return DoubleTag.class; + case NBTConstants.TYPE_BYTE_ARRAY: + return ByteArrayTag.class; + case NBTConstants.TYPE_STRING: + return StringTag.class; + case NBTConstants.TYPE_LIST: + return ListTag.class; + case NBTConstants.TYPE_COMPOUND: + return CompoundTag.class; + case NBTConstants.TYPE_INT_ARRAY: + return IntArrayTag.class; + case NBTConstants.TYPE_LONG_ARRAY: + return LongArrayTag.class; + default: + throw new IllegalArgumentException("Invalid tag type : " + type + + "."); + } + } + + /** + * Read a vector from a list tag containing ideally three values: the + * X, Y, and Z components. + * + *

For values that are unavailable, their values will be 0.

+ * + * @param listTag the list tag + * @return a vector + */ + public static Vector3 toVector(ListTag listTag) { + checkNotNull(listTag); + return Vector3.at(listTag.asDouble(0), listTag.asDouble(1), listTag.asDouble(2)); + } + + /** + * Get child tag of a NBT structure. + * + * @param items the map to read from + * @param key the key to look for + * @param expected the expected NBT class type + * @return child tag + * @throws InvalidFormatException if the format of the items is invalid + */ + public static T getChildTag(Map items, String key, Class expected) throws InvalidFormatException { + if (!items.containsKey(key)) { + throw new InvalidFormatException("Missing a \"" + key + "\" tag"); + } + Tag tag = items.get(key); + if (!expected.isInstance(tag)) { + throw new InvalidFormatException(key + " tag is not of tag type " + expected.getName()); + } + return expected.cast(tag); + } + +} diff --git a/src/main/java/com/sk89q/jnbt/NamedTag.java b/src/main/java/com/sk89q/jnbt/NamedTag.java new file mode 100644 index 0000000..c7089e3 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/NamedTag.java @@ -0,0 +1,63 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A tag that has a name. + */ +public class NamedTag { + + private final String name; + private final Tag tag; + + /** + * Create a new named tag. + * + * @param name the name + * @param tag the tag + */ + public NamedTag(String name, Tag tag) { + checkNotNull(name); + checkNotNull(tag); + this.name = name; + this.tag = tag; + } + + /** + * Get the name of the tag. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Get the tag. + * + * @return the tag + */ + public Tag getTag() { + return tag; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/ShortTag.java b/src/main/java/com/sk89q/jnbt/ShortTag.java new file mode 100644 index 0000000..f8224ab --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/ShortTag.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +/** + * The {@code TAG_Short} tag. + */ +public final class ShortTag extends Tag { + + private final short value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public ShortTag(short value) { + super(); + this.value = value; + } + + @Override + public Short getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_Short(" + value + ")"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/StringTag.java b/src/main/java/com/sk89q/jnbt/StringTag.java new file mode 100644 index 0000000..3727f8d --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/StringTag.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The {@code TAG_String} tag. + */ +public final class StringTag extends Tag { + + private final String value; + + /** + * Creates the tag with an empty name. + * + * @param value the value of the tag + */ + public StringTag(String value) { + super(); + checkNotNull(value); + this.value = value; + } + + @Override + public String getValue() { + return value; + } + + @Override + public String toString() { + return "TAG_String(" + value + ")"; + } + +} diff --git a/src/main/java/com/sk89q/jnbt/Tag.java b/src/main/java/com/sk89q/jnbt/Tag.java new file mode 100644 index 0000000..a94b3b3 --- /dev/null +++ b/src/main/java/com/sk89q/jnbt/Tag.java @@ -0,0 +1,34 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.jnbt; + +/** + * Represents a NBT tag. + */ +public abstract class Tag { + + /** + * Gets the value of this tag. + * + * @return the value + */ + public abstract Object getValue(); + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/Command.java b/src/main/java/com/sk89q/minecraft/util/commands/Command.java new file mode 100644 index 0000000..711a535 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/Command.java @@ -0,0 +1,93 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This annotation indicates a command. Methods should be marked with this + * annotation to tell {@link CommandsManager} that the method is a command. + * Note that the method name can actually be anything. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Command { + + /** + * A list of aliases for the command. The first alias is the most + * important -- it is the main name of the command. (The method name + * is never used for anything). + * + * @return Aliases for a command + */ + String[] aliases(); + + /** + * Usage instruction. Example text for usage could be + * {@code [-h harps] [name] [message]}. + * + * @return Usage instructions for a command + */ + String usage() default ""; + + /** + * @return A short description for the command. + */ + String desc(); + + /** + * The minimum number of arguments. This should be 0 or above. + * + * @return the minimum number of arguments + */ + int min() default 0; + + /** + * The maximum number of arguments. Use -1 for an unlimited number + * of arguments. + * + * @return the maximum number of arguments + */ + int max() default -1; + + /** + * Flags allow special processing for flags such as -h in the command, + * allowing users to easily turn on a flag. This is a string with + * each character being a flag. Use A-Z and a-z as possible flags. + * Appending a flag with a : makes the flag character before a value flag, + * meaning that if it is given it must have a value + * + * @return Flags matching a-zA-Z + */ + String flags() default ""; + + /** + * @return A long description for the command. + */ + String help() default ""; + + /** + * Get whether any flag can be used. + * + * @return true if so + */ + boolean anyFlags() default false; + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/CommandAlias.java b/src/main/java/com/sk89q/minecraft/util/commands/CommandAlias.java new file mode 100644 index 0000000..5c3eed5 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/CommandAlias.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Any command with this annotation will run the raw command as shown in the + * thing, as long as it is registered in the current {@link CommandsManager}. + * Mostly to move commands around without breaking things. + */ + +@Retention(RetentionPolicy.RUNTIME) +public @interface CommandAlias { + + /** + * Get the raw {@link CommandsManager}-formatted command arg array to run + * + * @return the command + */ + String[] value(); +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java b/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java new file mode 100644 index 0000000..e3340db --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java @@ -0,0 +1,362 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class CommandContext { + + protected final String command; + protected final List parsedArgs; + + protected final List originalArgIndices; + protected final String[] originalArgs; + protected final Set booleanFlags = new HashSet<>(); + protected final Map valueFlags = new HashMap<>(); + protected final SuggestionContext suggestionContext; + protected final CommandLocals locals; + + public static String[] split(String args) { + return args.split(" ", -1); + } + + public CommandContext(String args) throws CommandException { + this(args.split(" ", -1), null); + } + + public CommandContext(String[] args) throws CommandException { + this(args, null); + } + + public CommandContext(String args, Set valueFlags) throws CommandException { + this(args.split(" ", -1), valueFlags); + } + + public CommandContext(String args, Set valueFlags, boolean allowHangingFlag) + throws CommandException { + this(args.split(" ", -1), valueFlags, allowHangingFlag, new CommandLocals()); + } + + public CommandContext(String[] args, Set valueFlags) throws CommandException { + this(args, valueFlags, false, null); + } + + /** + * Parse the given array of arguments. + * + *

Empty arguments are removed from the list of arguments.

+ * + * @param args an array with arguments + * @param valueFlags a set containing all value flags (pass null to disable value flag parsing) + * @param allowHangingFlag true if hanging flags are allowed + * @param locals the locals, null to create empty one + * @throws CommandException thrown on a parsing error + */ + public CommandContext(String[] args, Set valueFlags, boolean allowHangingFlag, CommandLocals locals) throws CommandException { + this(args, valueFlags, allowHangingFlag, locals, true); + } + + /** + * Parse the given array of arguments. + * + *

Empty arguments are removed from the list of arguments.

+ * + * @param args an array with arguments + * @param valueFlags a set containing all value flags (pass null to disable value flag parsing) + * @param allowHangingFlag true if hanging flags are allowed + * @param locals the locals, null to create empty one + * @param parseFlags where to parse flags + * @throws CommandException thrown on a parsing error + */ + public CommandContext(String[] args, Set valueFlags, boolean allowHangingFlag, CommandLocals locals, boolean parseFlags) throws CommandException { + if (valueFlags == null) { + valueFlags = Collections.emptySet(); + } + + originalArgs = args; + command = args[0]; + this.locals = locals != null ? locals : new CommandLocals(); + boolean isHanging = false; + SuggestionContext suggestionContext = SuggestionContext.hangingValue(); + + // Eliminate empty args and combine multiword args first + List argIndexList = new ArrayList<>(args.length); + List argList = new ArrayList<>(args.length); + for (int i = 1; i < args.length; ++i) { + isHanging = false; + + String arg = args[i]; + if (arg.isEmpty()) { + isHanging = true; + continue; + } + + argIndexList.add(i); + + switch (arg.charAt(0)) { + case '\'': + case '"': + final StringBuilder build = new StringBuilder(); + final char quotedChar = arg.charAt(0); + + int endIndex; + for (endIndex = i; endIndex < args.length; ++endIndex) { + final String arg2 = args[endIndex]; + if (arg2.charAt(arg2.length() - 1) == quotedChar && arg2.length() > 1) { + if (endIndex != i) build.append(' '); + build.append(arg2.substring(endIndex == i ? 1 : 0, arg2.length() - 1)); + break; + } else if (endIndex == i) { + build.append(arg2.substring(1)); + } else { + build.append(' ').append(arg2); + } + } + + if (endIndex < args.length) { + arg = build.toString(); + i = endIndex; + } + + // In case there is an empty quoted string + if (arg.isEmpty()) { + continue; + } + // else raise exception about hanging quotes? + } + argList.add(arg); + } + + // Then flags + + this.originalArgIndices = new ArrayList<>(argIndexList.size()); + this.parsedArgs = new ArrayList<>(argList.size()); + + if (parseFlags) { + for (int nextArg = 0; nextArg < argList.size(); ) { + // Fetch argument + String arg = argList.get(nextArg++); + suggestionContext = SuggestionContext.hangingValue(); + + // Not a flag? + if (arg.charAt(0) != '-' || arg.length() == 1 || !arg.matches("^-[a-zA-Z\\?]+$")) { + if (!isHanging) { + suggestionContext = SuggestionContext.lastValue(); + } + + originalArgIndices.add(argIndexList.get(nextArg - 1)); + parsedArgs.add(arg); + continue; + } + + // Handle flag parsing terminator -- + if (arg.equals("--")) { + while (nextArg < argList.size()) { + originalArgIndices.add(argIndexList.get(nextArg)); + parsedArgs.add(argList.get(nextArg++)); + } + break; + } + + // Go through the flag characters + for (int i = 1; i < arg.length(); ++i) { + char flagName = arg.charAt(i); + + if (valueFlags.contains(flagName)) { + if (this.valueFlags.containsKey(flagName)) { + throw new CommandException("Value flag '" + flagName + "' already given"); + } + + if (nextArg >= argList.size()) { + if (allowHangingFlag) { + suggestionContext = SuggestionContext.flag(flagName); + break; + } else { + throw new CommandException("No value specified for the '-" + flagName + "' flag."); + } + } + + // If it is a value flag, read another argument and add it + this.valueFlags.put(flagName, argList.get(nextArg++)); + if (!isHanging) { + suggestionContext = SuggestionContext.flag(flagName); + } + } else { + booleanFlags.add(flagName); + } + } + } + } else { + for (int i = 0; i < argList.size(); i++) { + String arg = argList.get(i); + originalArgIndices.add(argIndexList.get(i)); + parsedArgs.add(arg); + } + } + + this.suggestionContext = suggestionContext; + } + + public SuggestionContext getSuggestionContext() { + return suggestionContext; + } + + public String getCommand() { + return command; + } + + public boolean matches(String command) { + return this.command.equalsIgnoreCase(command); + } + + public String getString(int index) { + return parsedArgs.get(index); + } + + public String getString(int index, String def) { + return index < parsedArgs.size() ? parsedArgs.get(index) : def; + } + + public String getJoinedStrings(int initialIndex) { + initialIndex = originalArgIndices.get(initialIndex); + StringBuilder buffer = new StringBuilder(originalArgs[initialIndex]); + for (int i = initialIndex + 1; i < originalArgs.length; ++i) { + buffer.append(" ").append(originalArgs[i]); + } + return buffer.toString(); + } + + public String getRemainingString(int start) { + return getString(start, parsedArgs.size() - 1); + } + + public String getString(int start, int end) { + StringBuilder buffer = new StringBuilder(parsedArgs.get(start)); + for (int i = start + 1; i < end + 1; ++i) { + buffer.append(" ").append(parsedArgs.get(i)); + } + return buffer.toString(); + } + + public int getInteger(int index) throws NumberFormatException { + return Integer.parseInt(parsedArgs.get(index)); + } + + public int getInteger(int index, int def) throws NumberFormatException { + return index < parsedArgs.size() ? Integer.parseInt(parsedArgs.get(index)) : def; + } + + public double getDouble(int index) throws NumberFormatException { + return Double.parseDouble(parsedArgs.get(index)); + } + + public double getDouble(int index, double def) throws NumberFormatException { + return index < parsedArgs.size() ? Double.parseDouble(parsedArgs.get(index)) : def; + } + + public String[] getSlice(int index) { + String[] slice = new String[originalArgs.length - index]; + System.arraycopy(originalArgs, index, slice, 0, originalArgs.length - index); + return slice; + } + + public String[] getPaddedSlice(int index, int padding) { + String[] slice = new String[originalArgs.length - index + padding]; + System.arraycopy(originalArgs, index, slice, padding, originalArgs.length - index); + return slice; + } + + public String[] getParsedSlice(int index) { + String[] slice = new String[parsedArgs.size() - index]; + System.arraycopy(parsedArgs.toArray(new String[parsedArgs.size()]), index, slice, 0, parsedArgs.size() - index); + return slice; + } + + public String[] getParsedPaddedSlice(int index, int padding) { + String[] slice = new String[parsedArgs.size() - index + padding]; + System.arraycopy(parsedArgs.toArray(new String[parsedArgs.size()]), index, slice, padding, parsedArgs.size() - index); + return slice; + } + + public boolean hasFlag(char ch) { + return booleanFlags.contains(ch) || valueFlags.containsKey(ch); + } + + public Set getFlags() { + return booleanFlags; + } + + public Map getValueFlags() { + return valueFlags; + } + + public String getFlag(char ch) { + return valueFlags.get(ch); + } + + public String getFlag(char ch, String def) { + final String value = valueFlags.get(ch); + if (value == null) { + return def; + } + + return value; + } + + public int getFlagInteger(char ch) throws NumberFormatException { + return Integer.parseInt(valueFlags.get(ch)); + } + + public int getFlagInteger(char ch, int def) throws NumberFormatException { + final String value = valueFlags.get(ch); + if (value == null) { + return def; + } + + return Integer.parseInt(value); + } + + public double getFlagDouble(char ch) throws NumberFormatException { + return Double.parseDouble(valueFlags.get(ch)); + } + + public double getFlagDouble(char ch, double def) throws NumberFormatException { + final String value = valueFlags.get(ch); + if (value == null) { + return def; + } + + return Double.parseDouble(value); + } + + public int argsLength() { + return parsedArgs.size(); + } + + public CommandLocals getLocals() { + return locals; + } +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/CommandException.java b/src/main/java/com/sk89q/minecraft/util/commands/CommandException.java new file mode 100644 index 0000000..8459f51 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/CommandException.java @@ -0,0 +1,84 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +import javax.annotation.Nullable; + +public class CommandException extends Exception { + + private final List commandStack = new ArrayList<>(); + + public CommandException() { + super(); + } + + public CommandException(String message) { + super(message); + } + + public CommandException(String message, Throwable t) { + super(message, t); + } + + public CommandException(Throwable t) { + super(t); + } + + public void prependStack(String name) { + commandStack.add(name); + } + + /** + * Gets the command that was called, which will include the sub-command + * (i.e. "/br sphere"). + * + * @param prefix the command shebang character (such as "/") -- may be empty + * @param spacedSuffix a suffix to put at the end (optional) -- may be null + * @return the command that was used + */ + public String getCommandUsed(String prefix, @Nullable String spacedSuffix) { + checkNotNull(prefix); + StringBuilder builder = new StringBuilder(); + if (prefix != null) { + builder.append(prefix); + } + ListIterator li = commandStack.listIterator(commandStack.size()); + while (li.hasPrevious()) { + if (li.previousIndex() != commandStack.size() - 1) { + builder.append(" "); + } + builder.append(li.previous()); + } + if (spacedSuffix != null) { + if (builder.length() > 0) { + builder.append(" "); + } + builder.append(spacedSuffix); + } + return builder.toString().trim(); + } + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/CommandLocals.java b/src/main/java/com/sk89q/minecraft/util/commands/CommandLocals.java new file mode 100644 index 0000000..ca09305 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/CommandLocals.java @@ -0,0 +1,50 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import java.util.HashMap; +import java.util.Map; + +public class CommandLocals { + + private final Map locals = new HashMap<>(); + + public boolean containsKey(Object key) { + return locals.containsKey(key); + } + + public boolean containsValue(Object value) { + return locals.containsValue(value); + } + + public Object get(Object key) { + return locals.get(key); + } + + @SuppressWarnings("unchecked") + public T get(Class key) { + return (T) locals.get(key); + } + + public Object put(Object key, Object value) { + return locals.put(key, value); + } + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissions.java b/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissions.java new file mode 100644 index 0000000..1a0c5a1 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissions.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Indicates a list of permissions that should be checked. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface CommandPermissions { + + /** + * A list of permissions. Only one permission has to be met + * for the command to be permitted. + * + * @return a list of permissions strings + */ + String[] value(); + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissionsException.java b/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissionsException.java new file mode 100644 index 0000000..c2f2e86 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/CommandPermissionsException.java @@ -0,0 +1,27 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +/** + * Thrown when not enough permissions are satisfied. + */ +public class CommandPermissionsException extends CommandException { + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/CommandUsageException.java b/src/main/java/com/sk89q/minecraft/util/commands/CommandUsageException.java new file mode 100644 index 0000000..3639dab --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/CommandUsageException.java @@ -0,0 +1,34 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +public class CommandUsageException extends CommandException { + + protected String usage; + + public CommandUsageException(String message, String usage) { + super(message); + this.usage = usage; + } + + public String getUsage() { + return usage; + } +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java b/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java new file mode 100644 index 0000000..faf6b39 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java @@ -0,0 +1,586 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import org.apache.logging.log4j.Logger; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +/** + * Manager for handling commands. This allows you to easily process commands, + * including nested commands, by correctly annotating methods of a class. + * + *

To use this, it is merely a matter of registering classes containing + * the commands (as methods with the proper annotations) with the + * manager. When you want to process a command, use one of the + * {@code execute} methods. If something is wrong, such as incorrect + * usage, insufficient permissions, or a missing command altogether, an + * exception will be raised for upstream handling.

+ * + *

Methods of a class to be registered can be static, but if an injector + * is registered with the class, the instances of the command classes + * will be created automatically and methods will be called non-statically.

+ * + *

To mark a method as a command, use {@link Command}. For nested commands, + * see {@link NestedCommand}. To handle permissions, use + * {@link CommandPermissions}.

+ * + *

This uses Java reflection extensively, but to reduce the overhead of + * reflection, command lookups are completely cached on registration. This + * allows for fast command handling. Method invocation still has to be done + * with reflection, but this is quite fast in that of itself.

+ * + * @param command sender class + */ +@SuppressWarnings("ProtectedField") +@Deprecated +public abstract class CommandsManager { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + /** + * Mapping of commands (including aliases) with a description. Root + * commands are stored under a key of null, whereas child commands are + * cached under their respective {@link Method}. The child map has + * the key of the command name (one for each alias) with the + * method. + */ + protected Map> commands = new HashMap<>(); + + /** + * Used to store the instances associated with a method. + */ + protected Map instances = new HashMap<>(); + + /** + * Mapping of commands (not including aliases) with a description. This + * is only for top level commands. + */ + protected Map descs = new HashMap<>(); + + /** + * Stores the injector used to getInstance. + */ + protected Injector injector; + + /** + * Mapping of commands (not including aliases) with a description. This + * is only for top level commands. + */ + protected Map helpMessages = new HashMap<>(); + + /** + * Register an class that contains commands (denoted by {@link Command}. + * If no dependency injector is specified, then the methods of the + * class will be registered to be called statically. Otherwise, new + * instances will be created of the command classes and methods will + * not be called statically. + * + * @param cls the class to register + */ + public void register(Class cls) { + registerMethods(cls, null); + } + + /** + * Register an class that contains commands (denoted by {@link Command}. + * If no dependency injector is specified, then the methods of the + * class will be registered to be called statically. Otherwise, new + * instances will be created of the command classes and methods will + * not be called statically. A List of {@link Command} annotations from + * registered commands is returned. + * + * @param cls the class to register + * @return A List of {@link Command} annotations from registered commands, + * for use in eg. a dynamic command registration system. + */ + public List registerAndReturn(Class cls) { + return registerMethods(cls, null); + } + + /** + * Register the methods of a class. This will automatically construct + * instances as necessary. + * + * @param cls the class to register + * @param parent the parent method + * @return Commands Registered + */ + public List registerMethods(Class cls, Method parent) { + try { + if (getInjector() == null) { + return registerMethods(cls, parent, null); + } else { + Object obj = getInjector().getInstance(cls); + return registerMethods(cls, parent, obj); + } + } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { + LOGGER.error("Failed to register commands", e); + } + return null; + } + + /** + * Register the methods of a class. + * + * @param cls the class to register + * @param parent the parent method + * @param obj the object whose methods will become commands if they are annotated + * @return a list of commands + */ + private List registerMethods(Class cls, Method parent, Object obj) { + Map map; + List registered = new ArrayList<>(); + + // Make a new hash map to cache the commands for this class + // as looking up methods via reflection is fairly slow + if (commands.containsKey(parent)) { + map = commands.get(parent); + } else { + map = new HashMap<>(); + commands.put(parent, map); + } + + for (Method method : cls.getMethods()) { + if (!method.isAnnotationPresent(Command.class)) { + continue; + } + + boolean isStatic = Modifier.isStatic(method.getModifiers()); + + Command cmd = method.getAnnotation(Command.class); + + // Cache the aliases too + for (String alias : cmd.aliases()) { + map.put(alias, method); + } + + // We want to be able invoke with an instance + if (!isStatic) { + // Can't register this command if we don't have an instance + if (obj == null) { + continue; + } + + instances.put(method, obj); + } + + // Build a list of commands and their usage details, at least for + // root level commands + if (parent == null) { + final String commandName = cmd.aliases()[0]; + final String desc = cmd.desc(); + + final String usage = cmd.usage(); + if (usage.isEmpty()) { + descs.put(commandName, desc); + } else { + descs.put(commandName, usage + " - " + desc); + } + + String help = cmd.help(); + if (help.isEmpty()) { + help = desc; + } + + final CharSequence arguments = getArguments(cmd); + for (String alias : cmd.aliases()) { + final String helpMessage = "/" + alias + " " + arguments + "\n\n" + help; + final String key = alias.replaceAll("/", ""); + String previous = helpMessages.put(key, helpMessage); + + if (previous != null && !previous.replaceAll("^/[^ ]+ ", "").equals(helpMessage.replaceAll("^/[^ ]+ ", ""))) { + helpMessages.put(key, previous + "\n\n" + helpMessage); + } + } + + } + + // Add the command to the registered command list for return + registered.add(cmd); + + // Look for nested commands -- if there are any, those have + // to be cached too so that they can be quickly looked + // up when processing commands + if (method.isAnnotationPresent(NestedCommand.class)) { + NestedCommand nestedCmd = method.getAnnotation(NestedCommand.class); + + for (Class nestedCls : nestedCmd.value()) { + registerMethods(nestedCls, method); + } + } + } + + if (cls.getSuperclass() != null) { + registerMethods(cls.getSuperclass(), parent, obj); + } + + return registered; + } + + /** + * Checks to see whether there is a command named such at the root level. + * This will check aliases as well. + * + * @param command the command + * @return true if the command exists + */ + public boolean hasCommand(String command) { + return commands.get(null).containsKey(command.toLowerCase(Locale.ROOT)); + } + + /** + * Get a list of command descriptions. This is only for root commands. + * + * @return a map of commands + */ + public Map getCommands() { + return descs; + } + + /** + * Get the mapping of methods under a parent command. + * + * @return the mapping + */ + public Map> getMethods() { + return commands; + } + + /** + * Get a map from command name to help message. This is only for root commands. + * + * @return a map of help messages for each command + */ + public Map getHelpMessages() { + return helpMessages; + } + + /** + * Get the usage string for a command. + * + * @param args the arguments + * @param level the depth of the command + * @param cmd the command annotation + * @return the usage string + */ + protected String getUsage(String[] args, int level, Command cmd) { + final StringBuilder command = new StringBuilder(); + + command.append('/'); + + for (int i = 0; i <= level; ++i) { + command.append(args[i]); + command.append(' '); + } + command.append(getArguments(cmd)); + + final String help = cmd.help(); + if (!help.isEmpty()) { + command.append("\n\n"); + command.append(help); + } + + return command.toString(); + } + + protected CharSequence getArguments(Command cmd) { + final String flags = cmd.flags(); + + final StringBuilder command2 = new StringBuilder(); + if (!flags.isEmpty()) { + String flagString = flags.replaceAll(".:", ""); + if (!flagString.isEmpty()) { + command2.append("[-"); + for (int i = 0; i < flagString.length(); ++i) { + command2.append(flagString.charAt(i)); + } + command2.append("] "); + } + } + + command2.append(cmd.usage()); + + return command2; + } + + /** + * Get the usage string for a nested command. + * + * @param args the arguments + * @param level the depth of the command + * @param method the parent method + * @param player the player + * @return the usage string + * @throws CommandException on some error + */ + protected String getNestedUsage(String[] args, int level, Method method, T player) throws CommandException { + StringBuilder command = new StringBuilder(); + + command.append("/"); + + for (int i = 0; i <= level; ++i) { + command.append(args[i]).append(" "); + } + + Map map = commands.get(method); + boolean found = false; + + command.append("<"); + + Set allowedCommands = new HashSet<>(); + + for (Map.Entry entry : map.entrySet()) { + Method childMethod = entry.getValue(); + found = true; + + if (hasPermission(childMethod, player)) { + Command childCmd = childMethod.getAnnotation(Command.class); + + allowedCommands.add(childCmd.aliases()[0]); + } + } + + if (!allowedCommands.isEmpty()) { + command.append(StringUtil.joinString(allowedCommands, "|", 0)); + } else { + if (!found) { + command.append("?"); + } else { + //command.append("action"); + throw new CommandPermissionsException(); + } + } + + command.append(">"); + + return command.toString(); + } + + /** + * Attempt to execute a command. This version takes a separate command + * name (for the root command) and then a list of following arguments. + * + * @param cmd command to run + * @param args arguments + * @param player command source + * @param methodArgs method arguments + * @throws CommandException thrown when the command throws an error + */ + public void execute(String cmd, String[] args, T player, Object... methodArgs) throws CommandException { + + String[] newArgs = new String[args.length + 1]; + System.arraycopy(args, 0, newArgs, 1, args.length); + newArgs[0] = cmd; + Object[] newMethodArgs = new Object[methodArgs.length + 1]; + System.arraycopy(methodArgs, 0, newMethodArgs, 1, methodArgs.length); + + executeMethod(null, newArgs, player, newMethodArgs, 0); + } + + /** + * Attempt to execute a command. + * + * @param args the arguments + * @param player the player + * @param methodArgs the arguments for the method + * @throws CommandException thrown on command error + */ + public void execute(String[] args, T player, Object... methodArgs) throws CommandException { + Object[] newMethodArgs = new Object[methodArgs.length + 1]; + System.arraycopy(methodArgs, 0, newMethodArgs, 1, methodArgs.length); + executeMethod(null, args, player, newMethodArgs, 0); + } + + /** + * Attempt to execute a command. + * + * @param parent the parent method + * @param args an array of arguments + * @param player the player + * @param methodArgs the array of method arguments + * @param level the depth of the command + * @throws CommandException thrown on a command error + */ + public void executeMethod(Method parent, String[] args, T player, Object[] methodArgs, int level) throws CommandException { + String cmdName = args[level]; + + Map map = commands.get(parent); + Method method = map.get(cmdName.toLowerCase(Locale.ROOT)); + + if (method == null) { + if (parent == null) { // Root + throw new UnhandledCommandException(); + } else { + throw new MissingNestedCommandException("Unknown command: " + cmdName, + getNestedUsage(args, level - 1, parent, player)); + } + } + + checkPermission(player, method); + + int argsCount = args.length - 1 - level; + + // checks if we need to execute the body of the nested command method (false) + // or display the help what commands are available (true) + // this is all for an args count of 0 if it is > 0 and a NestedCommand Annotation is present + // it will always handle the methods that NestedCommand points to + // e.g.: + // - /cmd - @NestedCommand(executeBody = true) will go into the else loop and execute code in that method + // - /cmd - @NestedCommand(executeBody = true) will always go to the nested command class + // - /cmd - @NestedCommand(executeBody = false) will always go to the nested command class not matter the args + boolean executeNested = method.isAnnotationPresent(NestedCommand.class) + && (argsCount > 0 || !method.getAnnotation(NestedCommand.class).executeBody()); + + if (executeNested) { + if (argsCount == 0) { + throw new MissingNestedCommandException("Sub-command required.", + getNestedUsage(args, level, method, player)); + } else { + executeMethod(method, args, player, methodArgs, level + 1); + } + } else if (method.isAnnotationPresent(CommandAlias.class)) { + CommandAlias aCmd = method.getAnnotation(CommandAlias.class); + executeMethod(parent, aCmd.value(), player, methodArgs, level); + } else { + Command cmd = method.getAnnotation(Command.class); + + String[] newArgs = new String[args.length - level]; + System.arraycopy(args, level, newArgs, 0, args.length - level); + + final Set valueFlags = new HashSet<>(); + + char[] flags = cmd.flags().toCharArray(); + Set newFlags = new HashSet<>(); + for (int i = 0; i < flags.length; ++i) { + if (flags.length > i + 1 && flags[i + 1] == ':') { + valueFlags.add(flags[i]); + ++i; + } + newFlags.add(flags[i]); + } + + CommandContext context = new CommandContext(newArgs, valueFlags); + + if (context.argsLength() < cmd.min()) { + throw new CommandUsageException("Too few arguments.", getUsage(args, level, cmd)); + } + + if (cmd.max() != -1 && context.argsLength() > cmd.max()) { + throw new CommandUsageException("Too many arguments.", getUsage(args, level, cmd)); + } + + if (!cmd.anyFlags()) { + for (char flag : context.getFlags()) { + if (!newFlags.contains(flag)) { + throw new CommandUsageException("Unknown flag: " + flag, getUsage(args, level, cmd)); + } + } + } + + methodArgs[0] = context; + + Object instance = instances.get(method); + + invokeMethod(parent, args, player, method, instance, methodArgs, argsCount); + } + } + + protected void checkPermission(T player, Method method) throws CommandException { + if (!hasPermission(method, player)) { + throw new CommandPermissionsException(); + } + } + + public void invokeMethod(Method parent, String[] args, T player, Method method, Object instance, Object[] methodArgs, int level) throws CommandException { + try { + method.invoke(instance, methodArgs); + } catch (IllegalArgumentException | IllegalAccessException e) { + LOGGER.error("Failed to execute command", e); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof CommandException) { + throw (CommandException) e.getCause(); + } + + throw new WrappedCommandException(e.getCause()); + } + } + + /** + * Returns whether a player has access to a command. + * + * @param method the method + * @param player the player + * @return true if permission is granted + */ + protected boolean hasPermission(Method method, T player) { + CommandPermissions perms = method.getAnnotation(CommandPermissions.class); + if (perms == null) { + return true; + } + + for (String perm : perms.value()) { + if (hasPermission(player, perm)) { + return true; + } + } + + return false; + } + + /** + * Returns whether a player permission.. + * + * @param player the player + * @param permission the permission + * @return true if permission is granted + */ + public abstract boolean hasPermission(T player, String permission); + + /** + * Get the injector used to create new instances. This can be + * null, in which case only classes will be registered statically. + * + * @return an injector instance + */ + public Injector getInjector() { + return injector; + } + + /** + * Set the injector for creating new instances. + * + * @param injector injector or null + */ + public void setInjector(Injector injector) { + this.injector = injector; + } +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/Console.java b/src/main/java/com/sk89q/minecraft/util/commands/Console.java new file mode 100644 index 0000000..366cf11 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/Console.java @@ -0,0 +1,31 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This annotation indicates that a command can be used from the console. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Console { + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/Injector.java b/src/main/java/com/sk89q/minecraft/util/commands/Injector.java new file mode 100644 index 0000000..5100d07 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/Injector.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import java.lang.reflect.InvocationTargetException; + +/** + * Constructs new instances. + */ +public interface Injector { + + /** + * Constructs a new instance of the given class. + * + * @param cls class + * @return object + * @throws IllegalAccessException thrown on injection fault + * @throws InstantiationException thrown on injection fault + * @throws InvocationTargetException thrown on injection fault + */ + Object getInstance(Class cls) throws InvocationTargetException, IllegalAccessException, InstantiationException; + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/MissingNestedCommandException.java b/src/main/java/com/sk89q/minecraft/util/commands/MissingNestedCommandException.java new file mode 100644 index 0000000..290a29d --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/MissingNestedCommandException.java @@ -0,0 +1,28 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +public class MissingNestedCommandException extends CommandUsageException { + + public MissingNestedCommandException(String message, String usage) { + super(message, usage); + } + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/NestedCommand.java b/src/main/java/com/sk89q/minecraft/util/commands/NestedCommand.java new file mode 100644 index 0000000..076f921 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/NestedCommand.java @@ -0,0 +1,50 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Indicates a nested command. Mark methods with this annotation to tell + * {@link CommandsManager} that a method is merely a shell for child + * commands. Note that the body of a method marked with this annotation + * will never called. Additionally, not all fields of {@link Command} apply + * when it is used in conjunction with this annotation, although both + * are still required. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface NestedCommand { + + /** + * A list of classes with the child commands. + * + * @return a list of classes + */ + Class[] value(); + + /** + * If set to true it will execute the body of the tagged method. + * + * @return true to execute the body of the annotated method + */ + boolean executeBody() default false; + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/SimpleInjector.java b/src/main/java/com/sk89q/minecraft/util/commands/SimpleInjector.java new file mode 100644 index 0000000..dab1edd --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/SimpleInjector.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import org.apache.logging.log4j.Logger; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +public class SimpleInjector implements Injector { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private final Object[] args; + private final Class[] argClasses; + + public SimpleInjector(Object... args) { + this.args = args; + argClasses = new Class[args.length]; + for (int i = 0; i < args.length; ++i) { + argClasses[i] = args[i].getClass(); + } + } + + @Override + public Object getInstance(Class clazz) { + try { + Constructor ctr = clazz.getConstructor(argClasses); + ctr.setAccessible(true); + return ctr.newInstance(args); + } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) { + LOGGER.error("Error initializing commands class " + clazz, e); + return null; + } + } +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/SuggestionContext.java b/src/main/java/com/sk89q/minecraft/util/commands/SuggestionContext.java new file mode 100644 index 0000000..01a715c --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/SuggestionContext.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +public class SuggestionContext { + + private static final SuggestionContext FOR_LAST = new SuggestionContext(null, true); + private static final SuggestionContext FOR_HANGING = new SuggestionContext(null, false); + + private final Character flag; + private final boolean forLast; + + private SuggestionContext(Character flag, boolean forLast) { + this.flag = flag; + this.forLast = forLast; + } + + public boolean forHangingValue() { + return flag == null && !forLast; + } + + public boolean forLastValue() { + return flag == null && forLast; + } + + public boolean forFlag() { + return flag != null; + } + + public Character getFlag() { + return flag; + } + + @Override + public String toString() { + return forFlag() ? ("-" + getFlag()) : (forHangingValue() ? "hanging" : "last"); + } + + public static SuggestionContext flag(Character flag) { + return new SuggestionContext(flag, false); + } + + public static SuggestionContext lastValue() { + return FOR_LAST; + } + + public static SuggestionContext hangingValue() { + return FOR_HANGING; + } + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/UnhandledCommandException.java b/src/main/java/com/sk89q/minecraft/util/commands/UnhandledCommandException.java new file mode 100644 index 0000000..d9eec56 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/UnhandledCommandException.java @@ -0,0 +1,24 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +public class UnhandledCommandException extends CommandException { + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/WrappedCommandException.java b/src/main/java/com/sk89q/minecraft/util/commands/WrappedCommandException.java new file mode 100644 index 0000000..d7a9bee --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/WrappedCommandException.java @@ -0,0 +1,28 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.minecraft.util.commands; + +public class WrappedCommandException extends CommandException { + + public WrappedCommandException(Throwable t) { + super(t); + } + +} diff --git a/src/main/java/com/sk89q/minecraft/util/commands/package-info.java b/src/main/java/com/sk89q/minecraft/util/commands/package-info.java new file mode 100644 index 0000000..dbc3530 --- /dev/null +++ b/src/main/java/com/sk89q/minecraft/util/commands/package-info.java @@ -0,0 +1,25 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +/** + * This package contains the old command system. It is no longer in use. Please switch + * to Piston, Intake, ACF, or similar systems. + */ +@Deprecated +package com.sk89q.minecraft.util.commands; diff --git a/src/main/java/com/sk89q/util/ReflectionUtil.java b/src/main/java/com/sk89q/util/ReflectionUtil.java new file mode 100644 index 0000000..d0b5909 --- /dev/null +++ b/src/main/java/com/sk89q/util/ReflectionUtil.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.util; + +import java.lang.reflect.Field; + +public final class ReflectionUtil { + + private ReflectionUtil() { + } + + @SuppressWarnings("unchecked") + public static T getField(Object from, String name) { + Class checkClass = from.getClass(); + do { + try { + Field field = checkClass.getDeclaredField(name); + field.setAccessible(true); + return (T) field.get(from); + } catch (NoSuchFieldException | IllegalAccessException ignored) { + } + } while (checkClass.getSuperclass() != Object.class && ((checkClass = checkClass.getSuperclass()) != null)); + return null; + } + +} diff --git a/src/main/java/com/sk89q/util/StringUtil.java b/src/main/java/com/sk89q/util/StringUtil.java new file mode 100644 index 0000000..3368da7 --- /dev/null +++ b/src/main/java/com/sk89q/util/StringUtil.java @@ -0,0 +1,334 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * String utilities. + */ +public final class StringUtil { + + private StringUtil() { + } + + /** + * Trim a string if it is longer than a certain length. + * + * @param str the string + * @param len the length to trim to + * @return a new string + */ + public static String trimLength(String str, int len) { + if (str.length() > len) { + return str.substring(0, len); + } + + return str; + } + + /** + * Join an array of strings into a string. + * + * @param str the string array + * @param delimiter the delimiter + * @param initialIndex the initial index to start form + * @return a new string + */ + public static String joinString(String[] str, String delimiter, int initialIndex) { + if (str.length == 0) { + return ""; + } + StringBuilder buffer = new StringBuilder(str[initialIndex]); + for (int i = initialIndex + 1; i < str.length; ++i) { + buffer.append(delimiter).append(str[i]); + } + return buffer.toString(); + } + + /** + * Join an array of strings into a string. + * + * @param str the string array + * @param delimiter the delimiter + * @param initialIndex the initial index to start form + * @param quote the character to put around each entry + * @return a new string + */ + public static String joinQuotedString(String[] str, String delimiter, + int initialIndex, String quote) { + if (str.length == 0) { + return ""; + } + StringBuilder buffer = new StringBuilder(); + buffer.append(quote); + buffer.append(str[initialIndex]); + buffer.append(quote); + for (int i = initialIndex + 1; i < str.length; ++i) { + buffer.append(delimiter).append(quote).append(str[i]).append(quote); + } + return buffer.toString(); + } + + /** + * Join an array of strings into a string. + * + * @param str the string array + * @param delimiter the delimiter + * @return a new string + */ + public static String joinString(String[] str, String delimiter) { + return joinString(str, delimiter, 0); + } + + /** + * Join an array of strings into a string. + * + * @param str an array of objects + * @param delimiter the delimiter + * @param initialIndex the initial index to start form + * @return a new string + */ + public static String joinString(Object[] str, String delimiter, int initialIndex) { + if (str.length == 0) { + return ""; + } + StringBuilder buffer = new StringBuilder(str[initialIndex].toString()); + for (int i = initialIndex + 1; i < str.length; ++i) { + buffer.append(delimiter).append(str[i]); + } + return buffer.toString(); + } + + /** + * Join an array of strings into a string. + * + * @param str a list of integers + * @param delimiter the delimiter + * @param initialIndex the initial index to start form + * @return a new string + */ + public static String joinString(int[] str, String delimiter, int initialIndex) { + if (str.length == 0) { + return ""; + } + StringBuilder buffer = new StringBuilder(Integer.toString(str[initialIndex])); + for (int i = initialIndex + 1; i < str.length; ++i) { + buffer.append(delimiter).append(Integer.toString(str[i])); + } + return buffer.toString(); + } + + /** + * Join an list of strings into a string. + * + * @param str a list of strings + * @param delimiter the delimiter + * @param initialIndex the initial index to start form + * @return a new string + */ + public static String joinString(Collection str, String delimiter, int initialIndex) { + if (str.isEmpty()) { + return ""; + } + StringBuilder buffer = new StringBuilder(); + int i = 0; + for (Object o : str) { + if (i >= initialIndex) { + if (i > 0) { + buffer.append(delimiter); + } + + buffer.append(o); + } + ++i; + } + return buffer.toString(); + } + + /** + *

Find the Levenshtein distance between two Strings.

+ * + *

This is the number of changes needed to change one String into + * another, where each change is a single character modification (deletion, + * insertion or substitution).

+ * + *

The previous implementation of the Levenshtein distance algorithm + * was from http://www.merriampark.com/ld.htm

+ * + *

Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError + * which can occur when my Java implementation is used with very large strings.
+ * This implementation of the Levenshtein distance algorithm + * is from http://www.merriampark.com/ldjava.htm

+ * + *
+     * StringUtil.getLevenshteinDistance(null, *)             = IllegalArgumentException
+     * StringUtil.getLevenshteinDistance(*, null)             = IllegalArgumentException
+     * StringUtil.getLevenshteinDistance("","")               = 0
+     * StringUtil.getLevenshteinDistance("","a")              = 1
+     * StringUtil.getLevenshteinDistance("aaapppp", "")       = 7
+     * StringUtil.getLevenshteinDistance("frog", "fog")       = 1
+     * StringUtil.getLevenshteinDistance("fly", "ant")        = 3
+     * StringUtil.getLevenshteinDistance("elephant", "hippo") = 7
+     * StringUtil.getLevenshteinDistance("hippo", "elephant") = 7
+     * StringUtil.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
+     * StringUtil.getLevenshteinDistance("hello", "hallo")    = 1
+     * 
+ * + * @param s the first String, must not be null + * @param t the second String, must not be null + * @return result distance + * @throws IllegalArgumentException if either String input {@code null} + */ + public static int getLevenshteinDistance(String s, String t) { + if (s == null || t == null) { + throw new IllegalArgumentException("Strings must not be null"); + } + + /* + * The difference between this impl. and the previous is that, rather + * than creating and retaining a matrix of size s.length()+1 by + * t.length()+1, we maintain two single-dimensional arrays of length + * s.length()+1. The first, d, is the 'current working' distance array + * that maintains the newest distance cost counts as we iterate through + * the characters of String s. Each time we increment the index of + * String t we are comparing, d is copied to p, the second int[]. Doing + * so allows us to retain the previous cost counts as required by the + * algorithm (taking the minimum of the cost count to the left, up one, + * and diagonally up and to the left of the current cost count being + * calculated). (Note that the arrays aren't really copied anymore, just + * switched...this is clearly much better than cloning an array or doing + * a System.arraycopy() each time through the outer loop.) + * + * Effectively, the difference between the two implementations is this + * one does not cause an out of memory condition when calculating the LD + * over two very large strings. + */ + + int n = s.length(); // length of s + int m = t.length(); // length of t + + if (n == 0) { + return m; + } else if (m == 0) { + return n; + } + + int[] p = new int[n + 1]; // 'previous' cost array, horizontally + int[] d = new int[n + 1]; // cost array, horizontally + int[] _d; // placeholder to assist in swapping p and d + + // indexes into strings s and t + int i; // iterates through s + int j; // iterates through t + + char tj; // jth character of t + + int cost; // cost + + for (i = 0; i <= n; ++i) { + p[i] = i; + } + + for (j = 1; j <= m; ++j) { + tj = t.charAt(j - 1); + d[0] = j; + + for (i = 1; i <= n; ++i) { + cost = s.charAt(i - 1) == tj ? 0 : 1; + // minimum of cell to the left+1, to the top+1, diagonally left + // and up +cost + d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + + cost); + } + + // copy current distance counts to 'previous row' distance counts + _d = p; + p = d; + d = _d; + } + + // our last action in the above loop was to switch d and p, so p now + // actually has the most recent cost counts + return p[n]; + } + + public static > T lookup(Map lookup, String name, boolean fuzzy) { + String testName = name.replaceAll("[ _]", "").toLowerCase(Locale.ROOT); + + T type = lookup.get(testName); + if (type != null) { + return type; + } + + if (!fuzzy) { + return null; + } + + int minDist = -1; + + for (Map.Entry entry : lookup.entrySet()) { + final String key = entry.getKey(); + if (key.charAt(0) != testName.charAt(0)) { + continue; + } + + int dist = getLevenshteinDistance(key, testName); + + if ((dist < minDist || minDist == -1) && dist < 2) { + minDist = dist; + type = entry.getValue(); + } + } + + return type; + } + + public static List parseListInQuotes(String[] input, char delimiter, char quoteOpen, char quoteClose) { + return parseListInQuotes(input, delimiter, quoteOpen, quoteClose, false); + } + + public static List parseListInQuotes(String[] input, char delimiter, char quoteOpen, char quoteClose, boolean appendLeftover) { + List parsableBlocks = new ArrayList<>(); + StringBuilder buffer = new StringBuilder(); + for (String split : input) { + if (split.indexOf(quoteOpen) != -1 && split.indexOf(quoteClose) == -1) { + buffer.append(split).append(delimiter); + } else if (split.indexOf(quoteClose) != -1 && split.indexOf(quoteOpen) == -1) { + buffer.append(split); + parsableBlocks.add(buffer.toString()); + buffer = new StringBuilder(); + } else if (buffer.length() == 0) { + parsableBlocks.add(split); + } else { + buffer.append(split).append(delimiter); + } + } + if (appendLeftover && buffer.length() != 0) { + parsableBlocks.add(buffer.delete(buffer.length() - 1, buffer.length()).toString()); + } + + return parsableBlocks; + } +} diff --git a/src/main/java/com/sk89q/util/yaml/YAMLFormat.java b/src/main/java/com/sk89q/util/yaml/YAMLFormat.java new file mode 100644 index 0000000..451b713 --- /dev/null +++ b/src/main/java/com/sk89q/util/yaml/YAMLFormat.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.util.yaml; + +import org.yaml.snakeyaml.DumperOptions.FlowStyle; + +public enum YAMLFormat { + EXTENDED(FlowStyle.BLOCK), + COMPACT(FlowStyle.AUTO); + + private final FlowStyle style; + + YAMLFormat(FlowStyle style) { + this.style = style; + } + + public FlowStyle getStyle() { + return style; + } +} diff --git a/src/main/java/com/sk89q/util/yaml/YAMLNode.java b/src/main/java/com/sk89q/util/yaml/YAMLNode.java new file mode 100644 index 0000000..ab547a5 --- /dev/null +++ b/src/main/java/com/sk89q/util/yaml/YAMLNode.java @@ -0,0 +1,846 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.util.yaml; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.math.Vector3; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * Represents a configuration node. + */ +public class YAMLNode { + + protected Map root; + private boolean writeDefaults; + + public YAMLNode(Map root, boolean writeDefaults) { + this.root = root; + this.writeDefaults = writeDefaults; + } + + /** + * Return the underlying map. + * + * @return the map + */ + public Map getMap() { + return root; + } + + /** + * Clear all nodes. + */ + public void clear() { + root.clear(); + } + + /** + * Gets a property at a location. This will either return an Object + * or null, with null meaning that no configuration value exists at + * that location. This could potentially return a default value (not yet + * implemented) as defined by a plugin, if this is a plugin-tied + * configuration. + * + * @param path path to node (dot notation) + * @return object or null + */ + @SuppressWarnings("unchecked") + public Object getProperty(String path) { + if (!path.contains(".")) { + Object val = root.get(path); + if (val == null) { + return null; + } + return val; + } + + String[] parts = path.split("\\."); + Map node = root; + + for (int i = 0; i < parts.length; i++) { + Object o = node.get(parts[i]); + + if (o == null) { + return null; + } + + if (i == parts.length - 1) { + return o; + } + + try { + node = (Map) o; + } catch (ClassCastException e) { + return null; + } + } + + return null; + } + + /** + * Prepare a value for serialization, in case it's not a native type + * (and we don't want to serialize objects as YAML objects). + * + * @param value the value to serialize + * @return the new object + */ + private Object prepareSerialization(Object value) { + if (value instanceof Vector3) { + Map out = new LinkedHashMap<>(); + Vector3 vec = (Vector3) value; + out.put("x", vec.getX()); + out.put("y", vec.getY()); + out.put("z", vec.getZ()); + return out; + } else if (value instanceof BlockVector3) { + Map out = new LinkedHashMap<>(); + BlockVector3 vec = (BlockVector3) value; + out.put("x", vec.getBlockX()); + out.put("y", vec.getBlockY()); + out.put("z", vec.getBlockZ()); + return out; + } else if (value instanceof Vector2) { + Map out = new LinkedHashMap<>(); + Vector2 vec = (Vector2) value; + out.put("x", vec.getX()); + out.put("z", vec.getZ()); + return out; + } else if (value instanceof BlockVector2) { + Map out = new LinkedHashMap<>(); + BlockVector2 vec = (BlockVector2) value; + out.put("x", vec.getBlockX()); + out.put("z", vec.getBlockZ()); + return out; + } + + return value; + } + + /** + * Set the property at a location. This will override existing + * configuration data to have it conform to key/value mappings. + * + * @param path the path + * @param value the new value + */ + @SuppressWarnings("unchecked") + public void setProperty(String path, Object value) { + value = prepareSerialization(value); + + if (!path.contains(".")) { + root.put(path, value); + return; + } + + String[] parts = path.split("\\."); + Map node = root; + + for (int i = 0; i < parts.length; i++) { + Object o = node.get(parts[i]); + + // Found our target! + if (i == parts.length - 1) { + node.put(parts[i], value); + return; + } + + if (!(o instanceof Map)) { + // This will override existing configuration data! + o = new LinkedHashMap(); + node.put(parts[i], o); + } + + node = (Map) o; + } + } + + /** + * Adds a new node to the given path. The returned object is a reference + * to the new node. This method will replace an existing node at + * the same path. See {@code setProperty}. + * + * @param path the path + * @return a node for the path + */ + public YAMLNode addNode(String path) { + Map map = new LinkedHashMap<>(); + YAMLNode node = new YAMLNode(map, writeDefaults); + setProperty(path, map); + return node; + } + + /** + * Gets a string at a location. This will either return an String + * or null, with null meaning that no configuration value exists at + * that location. If the object at the particular location is not actually + * a string, it will be converted to its string representation. + * + * @param path path to node (dot notation) + * @return string or null + */ + public String getString(String path) { + Object o = getProperty(path); + if (o == null) { + return null; + } + return o.toString(); + } + + /** + * Gets a vector at a location. This will either return an Vector + * or a null. If the object at the particular location is not + * actually a string, it will be converted to its string representation. + * + * @param path path to node (dot notation) + * @return string or default + */ + public Vector3 getVector(String path) { + YAMLNode o = getNode(path); + if (o == null) { + return null; + } + + Double x = o.getDouble("x"); + Double y = o.getDouble("y"); + Double z = o.getDouble("z"); + + if (x == null || y == null || z == null) { + return null; + } + + return Vector3.at(x, y, z); + } + + /** + * Gets a 2D vector at a location. This will either return an Vector + * or a null. If the object at the particular location is not + * actually a string, it will be converted to its string representation. + * + * @param path path to node (dot notation) + * @return string or default + */ + public Vector2 getVector2(String path) { + YAMLNode o = getNode(path); + if (o == null) { + return null; + } + + Double x = o.getDouble("x"); + Double z = o.getDouble("z"); + + if (x == null || z == null) { + return null; + } + + return Vector2.at(x, z); + } + + /** + * Gets a string at a location. This will either return an Vector + * or the default value. If the object at the particular location is not + * actually a string, it will be converted to its string representation. + * + * @param path path to node (dot notation) + * @param def default value + * @return string or default + */ + public Vector3 getVector(String path, Vector3 def) { + Vector3 v = getVector(path); + if (v == null) { + if (writeDefaults) { + setProperty(path, def); + } + return def; + } + return v; + } + + /** + * Gets a string at a location. This will either return an String + * or the default value. If the object at the particular location is not + * actually a string, it will be converted to its string representation. + * + * @param path path to node (dot notation) + * @param def default value + * @return string or default + */ + public String getString(String path, String def) { + String o = getString(path); + if (o == null) { + if (writeDefaults) { + setProperty(path, def); + } + return def; + } + return o; + } + + /** + * Gets an integer at a location. This will either return an integer + * or null. If the object at the particular location is not + * actually a integer, the default value will be returned. However, other + * number types will be casted to an integer. + * + * @param path path to node (dot notation) + * @return integer or null + */ + public Integer getInt(String path) { + Integer o = castInt(getProperty(path)); + if (o == null) { + return null; + } else { + return o; + } + } + + /** + * Gets an integer at a location. This will either return an integer + * or the default value. If the object at the particular location is not + * actually a integer, the default value will be returned. However, other + * number types will be casted to an integer. + * + * @param path path to node (dot notation) + * @param def default value + * @return int or default + */ + public int getInt(String path, int def) { + Integer o = castInt(getProperty(path)); + if (o == null) { + if (writeDefaults) { + setProperty(path, def); + } + return def; + } else { + return o; + } + } + + /** + * Gets a double at a location. This will either return an double + * or null. If the object at the particular location is not + * actually a double, the default value will be returned. However, other + * number types will be casted to an double. + * + * @param path path to node (dot notation) + * @return double or null + */ + public Double getDouble(String path) { + Double o = castDouble(getProperty(path)); + if (o == null) { + return null; + } else { + return o; + } + } + + /** + * Gets a double at a location. This will either return an double + * or the default value. If the object at the particular location is not + * actually a double, the default value will be returned. However, other + * number types will be casted to an double. + * + * @param path path to node (dot notation) + * @param def default value + * @return double or default + */ + public double getDouble(String path, double def) { + Double o = castDouble(getProperty(path)); + if (o == null) { + if (writeDefaults) { + setProperty(path, def); + } + return def; + } else { + return o; + } + } + + /** + * Gets a boolean at a location. This will either return an boolean + * or null. If the object at the particular location is not + * actually a boolean, the default value will be returned. + * + * @param path path to node (dot notation) + * @return boolean or null + */ + public Boolean getBoolean(String path) { + Boolean o = castBoolean(getProperty(path)); + if (o == null) { + return null; + } else { + return o; + } + } + + /** + * Gets a boolean at a location. This will either return an boolean + * or the default value. If the object at the particular location is not + * actually a boolean, the default value will be returned. + * + * @param path path to node (dot notation) + * @param def default value + * @return boolean or default + */ + public boolean getBoolean(String path, boolean def) { + Boolean o = castBoolean(getProperty(path)); + if (o == null) { + if (writeDefaults) { + setProperty(path, def); + } + return def; + } else { + return o; + } + } + + /** + * Get a list of keys at a location. If the map at the particular location + * does not exist or it is not a map, null will be returned. + * + * @param path path to node (dot notation) + * @return list of keys + */ + @SuppressWarnings("unchecked") + public List getKeys(String path) { + if (path == null) { + return new ArrayList<>(root.keySet()); + } + Object o = getProperty(path); + if (o == null) { + return null; + } else if (o instanceof Map) { + return new ArrayList<>(((Map) o).keySet()); + } else { + return null; + } + } + + /** + * Gets a list of objects at a location. If the list is not defined, + * null will be returned. The node must be an actual list. + * + * @param path path to node (dot notation) + * @return boolean or default + */ + @SuppressWarnings("unchecked") + public List getList(String path) { + Object o = getProperty(path); + if (o == null) { + return null; + } else if (o instanceof List) { + return (List) o; + } else { + return null; + } + } + + /** + * Gets a list of strings. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. If an item in the list + * is not a string, it will be converted to a string. The node must be + * an actual list and not just a string. + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of strings + */ + public List getStringList(String path, List def) { + List raw = getList(path); + if (raw == null) { + if (writeDefaults && def != null) { + setProperty(path, def); + } + return def != null ? def : new ArrayList<>(); + } + + List list = new ArrayList<>(); + for (Object o : raw) { + if (o == null) { + continue; + } + + list.add(o.toString()); + } + + return list; + } + + /** + * Gets a list of integers. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual list and not just an integer. + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getIntList(String path, List def) { + List raw = getList(path); + if (raw == null) { + if (writeDefaults && def != null) { + setProperty(path, def); + } + return def != null ? def : new ArrayList<>(); + } + + List list = new ArrayList<>(); + for (Object o : raw) { + Integer i = castInt(o); + if (i != null) { + list.add(i); + } + } + + return list; + } + + /** + * Gets a list of doubles. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual list and cannot be just a double. + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getDoubleList(String path, List def) { + List raw = getList(path); + if (raw == null) { + if (writeDefaults && def != null) { + setProperty(path, def); + } + return def != null ? def : new ArrayList<>(); + } + + List list = new ArrayList<>(); + for (Object o : raw) { + Double i = castDouble(o); + if (i != null) { + list.add(i); + } + } + + return list; + } + + /** + * Gets a list of booleans. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual list and cannot be just a boolean, + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getBooleanList(String path, List def) { + List raw = getList(path); + if (raw == null) { + if (writeDefaults && def != null) { + setProperty(path, def); + } + return def != null ? def : new ArrayList<>(); + } + + List list = new ArrayList<>(); + for (Object o : raw) { + Boolean tetsu = castBoolean(o); + if (tetsu != null) { + list.add(tetsu); + } + } + + return list; + } + + /** + * Gets a list of vectors. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual node and cannot be just a vector, + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getVectorList(String path, List def) { + List raw = getNodeList(path, null); + List list = new ArrayList<>(); + + for (YAMLNode o : raw) { + Double x = o.getDouble("x"); + Double y = o.getDouble("y"); + Double z = o.getDouble("z"); + + if (x == null || y == null || z == null) { + continue; + } + + list.add(Vector3.at(x, y, z)); + } + + return list; + } + + /** + * Gets a list of 2D vectors. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual node and cannot be just a vector, + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getVector2List(String path, List def) { + + List raw = getNodeList(path, null); + List list = new ArrayList<>(); + + for (YAMLNode o : raw) { + Double x = o.getDouble("x"); + Double z = o.getDouble("z"); + + if (x == null || z == null) { + continue; + } + + list.add(Vector2.at(x, z)); + } + + return list; + } + + /** + * Gets a list of 2D vectors. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual node and cannot be just a vector, + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getBlockVector2List(String path, List def) { + + List raw = getNodeList(path, null); + List list = new ArrayList<>(); + + for (YAMLNode o : raw) { + Double x = o.getDouble("x"); + Double z = o.getDouble("z"); + + if (x == null || z == null) { + continue; + } + + list.add(BlockVector2.at(x, z)); + } + + return list; + } + + /** + * Gets a list of nodes. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual node and cannot be just a boolean, + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + @SuppressWarnings("unchecked") + public List getNodeList(String path, List def) { + List raw = getList(path); + if (raw == null) { + if (writeDefaults && def != null) { + setProperty(path, def); + } + return def != null ? def : new ArrayList<>(); + } + + List list = new ArrayList<>(); + for (Object o : raw) { + if (o instanceof Map) { + list.add(new YAMLNode((Map) o, writeDefaults)); + } + } + + return list; + } + + /** + * Get a configuration node at a path. If the node doesn't exist or the + * path does not lead to a node, null will be returned. A node has + * key/value mappings. + * + * @param path the path + * @return node or null + */ + @Nullable + @SuppressWarnings("unchecked") + public YAMLNode getNode(String path) { + Object raw = getProperty(path); + if (raw instanceof Map) { + return new YAMLNode((Map) raw, writeDefaults); + } + + return null; + } + + /** + * Get a list of nodes at a location. If the map at the particular location + * does not exist or it is not a map, null will be returned. + * + * @param path path to node (dot notation) + * @return map of nodes + */ + @SuppressWarnings("unchecked") + public Map getNodes(String path) { + Object o = getProperty(path); + if (o == null) { + return null; + } else if (o instanceof Map) { + Map nodes = + new LinkedHashMap<>(); + + for (Map.Entry entry : ((Map) o).entrySet()) { + if (entry.getValue() instanceof Map) { + nodes.put(entry.getKey(), + new YAMLNode((Map) entry.getValue(), writeDefaults)); + } + } + + return nodes; + } else { + return null; + } + } + + /** + * Casts a value to an integer. May return null. + * + * @param o the object + * @return an integer or null + */ + @Nullable + private static Integer castInt(Object o) { + if (o == null) { + return null; + } else if (o instanceof Number) { + return ((Number) o).intValue(); + } else { + return null; + } + } + + /** + * Casts a value to a double. May return null. + * + * @param o the object + * @return a double or null + */ + @Nullable + private static Double castDouble(Object o) { + if (o == null) { + return null; + } else if (o instanceof Number) { + return ((Number) o).doubleValue(); + } else { + return null; + } + } + + /** + * Casts a value to a boolean. May return null. + * + * @param o the object + * @return a boolean or null + */ + @Nullable + private static Boolean castBoolean(Object o) { + if (o == null) { + return null; + } else if (o instanceof Boolean) { + return (Boolean) o; + } else { + return null; + } + } + + /** + * Remove the property at a location. This will override existing + * configuration data to have it conform to key/value mappings. + * + * @param path a path + */ + @SuppressWarnings("unchecked") + public void removeProperty(String path) { + if (!path.contains(".")) { + root.remove(path); + return; + } + + String[] parts = path.split("\\."); + Map node = root; + + for (int i = 0; i < parts.length; i++) { + Object o = node.get(parts[i]); + + // Found our target! + if (i == parts.length - 1) { + node.remove(parts[i]); + return; + } + + node = (Map) o; + } + } + + public boolean writeDefaults() { + return writeDefaults; + } + + public void setWriteDefaults(boolean writeDefaults) { + this.writeDefaults = writeDefaults; + } + +} diff --git a/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java b/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java new file mode 100644 index 0000000..d1bd02e --- /dev/null +++ b/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java @@ -0,0 +1,318 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.util.yaml; + +import com.sk89q.util.StringUtil; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.LoaderOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.nodes.Tag; +import org.yaml.snakeyaml.reader.UnicodeReader; +import org.yaml.snakeyaml.representer.Representer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +/** + * YAML configuration loader. To use this class, construct it with path to + * a file and call its load() method. For specifying node paths in the + * various get*() methods, they support SK's path notation, allowing you to + * select child nodes by delimiting node names with periods. + * + *

+ * For example, given the following configuration file:

+ * + *
members:
+ *     - Hollie
+ *     - Jason
+ *     - Bobo
+ *     - Aya
+ *     - Tetsu
+ * worldguard:
+ *     fire:
+ *         spread: false
+ *         blocks: [cloth, rock, glass]
+ * sturmeh:
+ *     cool: false
+ *     eats:
+ *         babies: true
+ * + *

Calling code could access sturmeh's baby eating state by using + * {@code getBoolean("sturmeh.eats.babies", false)}. For lists, there are + * methods such as {@code getStringList} that will return a type safe list. + */ +public class YAMLProcessor extends YAMLNode { + + public static final String LINE_BREAK = DumperOptions.LineBreak.getPlatformLineBreak().getString(); + public static final char COMMENT_CHAR = '#'; + protected final Yaml yaml; + protected final File file; + protected String header = null; + protected YAMLFormat format; + + /* + * Map from property key to comment. Comment may have multiple lines that are newline-separated. + * Comments support based on ZerothAngel's AnnotatedYAMLConfiguration + * Comments are only supported with YAMLFormat.EXTENDED + */ + private final Map comments = new HashMap<>(); + + public YAMLProcessor(File file, boolean writeDefaults, YAMLFormat format) { + super(new LinkedHashMap<>(), writeDefaults); + this.format = format; + + DumperOptions dumperOptions = new DumperOptions(); + dumperOptions.setIndent(4); + dumperOptions.setDefaultFlowStyle(format.getStyle()); + Representer representer = new FancyRepresenter(); + representer.setDefaultFlowStyle(format.getStyle()); + LoaderOptions loaderOptions = new LoaderOptions(); + try { + int yamlAliasLimit = Integer.getInteger("worldedit.yaml.aliasLimit", 50); + loaderOptions.setMaxAliasesForCollections(yamlAliasLimit); + // 64 MB default + int yamlCodePointLimit = Integer.getInteger("worldedit.yaml.codePointLimit", 64 * 1024 * 1024); + loaderOptions.setCodePointLimit(yamlCodePointLimit); + } catch (NoSuchMethodError ignored) { + // pre-1.32 snakeyaml + } + + yaml = new Yaml(new SafeConstructor(loaderOptions), representer, dumperOptions, loaderOptions); + + this.file = file; + } + + public YAMLProcessor(File file, boolean writeDefaults) { + this(file, writeDefaults, YAMLFormat.COMPACT); + } + + /** + * Loads the configuration file. + * + * @throws IOException on load error + */ + public void load() throws IOException { + try (InputStream stream = getInputStream()) { + if (stream == null) { + throw new IOException("Stream is null!"); + } + read(yaml.load(new UnicodeReader(stream))); + } catch (YAMLProcessorException e) { + root = new LinkedHashMap<>(); + } + } + + /** + * Set the header for the file as a series of lines that are terminated + * by a new line sequence. + * + * @param headerLines header lines to prepend + */ + public void setHeader(String... headerLines) { + StringBuilder header = new StringBuilder(); + + for (String line : headerLines) { + if (header.length() > 0) { + header.append(LINE_BREAK); + } + header.append(line); + } + + setHeader(header.toString()); + } + + /** + * Set the header for the file. A header can be provided to prepend the + * YAML data output on configuration save. The header is + * printed raw and so must be manually commented if used. A new line will + * be appended after the header, however, if a header is provided. + * + * @param header header to prepend + */ + public void setHeader(String header) { + this.header = header; + } + + /** + * Return the set header. + * + * @return the header text + */ + public String getHeader() { + return header; + } + + /** + * Saves the configuration to disk. All errors are clobbered. + * + * @return true if it was successful + */ + public boolean save() { + + File parent = file.getParentFile(); + if (parent != null) { + parent.mkdirs(); + } + try (OutputStream stream = getOutputStream()) { + if (stream == null) { + return false; + } + OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8); + if (header != null) { + writer.append(header); + writer.append(LINE_BREAK); + } + if (comments.isEmpty() || format != YAMLFormat.EXTENDED) { + yaml.dump(root, writer); + } else { + // Iterate over each root-level property and dump + for (Entry entry: root.entrySet()) { + // Output comment, if present + String comment = comments.get(entry.getKey()); + if (comment != null) { + writer.append(LINE_BREAK); + writer.append(comment); + writer.append(LINE_BREAK); + } + + // Dump property + yaml.dump(Collections.singletonMap(entry.getKey(), entry.getValue()), writer); + } + } + return true; + } catch (IOException ignored) { + } + + return false; + } + + @SuppressWarnings("unchecked") + private void read(Object input) throws YAMLProcessorException { + try { + if (null == input) { + root = new LinkedHashMap<>(); + } else { + root = new LinkedHashMap<>((Map) input); + } + } catch (ClassCastException e) { + throw new YAMLProcessorException("Root document must be an key-value structure"); + } + } + + public InputStream getInputStream() throws IOException { + return new FileInputStream(file); + } + + public OutputStream getOutputStream() throws IOException { + return new FileOutputStream(file); + } + + /** + * Returns a root-level comment. + * + * @param key the property key + * @return the comment or {@code null} + */ + public String getComment(String key) { + return comments.get(key); + } + + public void setComment(String key, String comment) { + if (comment != null) { + setComment(key, comment.split("\\r?\\n")); + } else { + comments.remove(key); + } + } + + /** + * Set a root-level comment. + * + * @param key the property key + * @param comment the comment. May be {@code null}, in which case the comment + * is removed. + */ + public void setComment(String key, String... comment) { + if (comment != null && comment.length > 0) { + for (int i = 0; i < comment.length; ++i) { + if (!comment[i].matches("^" + COMMENT_CHAR + " ?")) { + comment[i] = COMMENT_CHAR + " " + comment[i]; + } + } + String s = StringUtil.joinString(comment, LINE_BREAK); + comments.put(key, s); + } else { + comments.remove(key); + } + } + + /** + * Returns root-level comments. + * + * @return map of root-level comments + */ + public Map getComments() { + return Collections.unmodifiableMap(comments); + } + + /** + * Set root-level comments from a map. + * + * @param comments comment map + */ + public void setComments(Map comments) { + this.comments.clear(); + if (comments != null) { + this.comments.putAll(comments); + } + } + + /** + * Get an empty ConfigurationNode for using as a default in methods that + * select a node from a node list. + * + * @param writeDefaults true to write default values when a property is + * requested that doesn't exist + * @return a node + */ + public static YAMLNode getEmptyNode(boolean writeDefaults) { + return new YAMLNode(new LinkedHashMap<>(), writeDefaults); + } + + private static class FancyRepresenter extends Representer { + private FancyRepresenter() { + super(new DumperOptions()); + this.nullRepresenter = o -> representScalar(Tag.NULL, ""); + } + } + +} diff --git a/src/main/java/com/sk89q/util/yaml/YAMLProcessorException.java b/src/main/java/com/sk89q/util/yaml/YAMLProcessorException.java new file mode 100644 index 0000000..07e95e4 --- /dev/null +++ b/src/main/java/com/sk89q/util/yaml/YAMLProcessorException.java @@ -0,0 +1,35 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.util.yaml; + +/** + * YAMLProcessor exception. + */ +public class YAMLProcessorException extends Exception { + + public YAMLProcessorException() { + super(); + } + + public YAMLProcessorException(String msg) { + super(msg); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/DisallowedItemException.java b/src/main/java/com/sk89q/worldedit/DisallowedItemException.java new file mode 100644 index 0000000..c42636d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/DisallowedItemException.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import com.sk89q.worldedit.extension.input.DisallowedUsageException; + +/** + * Thrown when a disallowed item is used. + * + * @deprecated Use {@link DisallowedUsageException} + */ +@Deprecated +public class DisallowedItemException extends WorldEditException { + + private final String type; + + public DisallowedItemException(String type) { + this.type = type; + } + + public DisallowedItemException(String type, String message) { + super(message); + this.type = type; + } + + public String getID() { + return type; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java new file mode 100644 index 0000000..30efe50 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -0,0 +1,2666 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.extent.*; +import com.sk89q.worldedit.extent.buffer.ForgetfulExtentBuffer; +import com.sk89q.worldedit.extent.cache.LastAccessExtentCache; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.extent.inventory.BlockBagExtent; +import com.sk89q.worldedit.extent.reorder.ChunkBatchingExtent; +import com.sk89q.worldedit.extent.reorder.MultiStageReorder; +import com.sk89q.worldedit.extent.validation.BlockChangeLimiter; +import com.sk89q.worldedit.extent.validation.DataValidatorExtent; +import com.sk89q.worldedit.extent.world.*; +import com.sk89q.worldedit.function.GroundFunction; +import com.sk89q.worldedit.function.RegionMaskingFilter; +import com.sk89q.worldedit.function.biome.BiomeReplace; +import com.sk89q.worldedit.function.block.*; +import com.sk89q.worldedit.function.generator.ForestGenerator; +import com.sk89q.worldedit.function.generator.GardenPatchGenerator; +import com.sk89q.worldedit.function.mask.*; +import com.sk89q.worldedit.function.operation.*; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.WaterloggedRemover; +import com.sk89q.worldedit.function.util.RegionOffset; +import com.sk89q.worldedit.function.visitor.*; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.history.changeset.BlockOptimizedHistory; +import com.sk89q.worldedit.history.changeset.ChangeSet; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.internal.expression.ExpressionTimeoutException; +import com.sk89q.worldedit.internal.expression.LocalSlot.Variable; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MathUtils; +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.interpolation.Interpolation; +import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation; +import com.sk89q.worldedit.math.interpolation.Node; +import com.sk89q.worldedit.math.noise.RandomNoise; +import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.regions.*; +import com.sk89q.worldedit.regions.shape.ArbitraryBiomeShape; +import com.sk89q.worldedit.regions.shape.ArbitraryShape; +import com.sk89q.worldedit.regions.shape.RegionShape; +import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.collection.BlockMap; +import com.sk89q.worldedit.util.collection.DoubleArrayList; +import com.sk89q.worldedit.util.eventbus.EventBus; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.NullWorld; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.*; +import com.sk89q.worldedit.world.registry.LegacyMapper; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.regions.Regions.*; + +/** + * An {@link Extent} that handles history, {@link BlockBag}s, change limits, + * block re-ordering, and much more. Most operations in WorldEdit use this class. + * + *

Most of the actual functionality is implemented with a number of other + * {@link Extent}s that are chained together. For example, history is logged + * using the {@link ChangeSetExtent}.

+ */ +@SuppressWarnings({"FieldCanBeLocal"}) +public class EditSession implements Extent, AutoCloseable { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + /** + * Used by {@link EditSession#setBlock(BlockVector3, BlockStateHolder, Stage)} to + * determine which {@link Extent}s should be bypassed. + */ + public enum Stage { + BEFORE_HISTORY, + BEFORE_REORDER, + BEFORE_CHANGE + } + + /** + * Reorder mode for {@link EditSession#setReorderMode(ReorderMode)}. + * + *

+ * MULTI_STAGE = Multi stage reorder, may not be great with mods. + * FAST = Use the fast mode. Good for mods. + * NONE = Place blocks without worrying about placement order. + *

+ */ + public enum ReorderMode { + MULTI_STAGE("multi"), + FAST("fast"), + NONE("none"); + + private final String displayName; + + ReorderMode(String displayName) { + this.displayName = displayName; + } + + public String getDisplayName() { + return this.displayName; + } + } + + @SuppressWarnings("ProtectedField") + protected final World world; + private final @Nullable Actor actor; + private final ChangeSet changeSet = new BlockOptimizedHistory(); + + private @Nullable SideEffectExtent sideEffectExtent; + private final SurvivalModeExtent survivalExtent; + private @Nullable ChunkBatchingExtent chunkBatchingExtent; + private final BlockBagExtent blockBagExtent; + private final MultiStageReorder reorderExtent; + private final MaskingExtent maskingExtent; + private final BlockChangeLimiter changeLimiter; + private final List watchdogExtents = new ArrayList<>(2); + + private final Extent bypassReorderHistory; + private final Extent bypassHistory; + private final Extent bypassNone; + + private final @Nullable List tracingExtents; + + private ReorderMode reorderMode = ReorderMode.MULTI_STAGE; + + private Mask oldMask; + + /** + * Construct the object with a maximum number of blocks and a block bag. + * + * @param eventBus the event bus + * @param world the world + * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit + * @param blockBag an optional {@link BlockBag} to use, otherwise null + * @param actor the actor that owns the session + * @param tracing if tracing is enabled. An actor is required if this is {@code true} + */ + EditSession(EventBus eventBus, World world, int maxBlocks, @Nullable BlockBag blockBag, + @Nullable Actor actor, + boolean tracing) { + checkNotNull(eventBus); + checkArgument(maxBlocks >= -1, "maxBlocks >= -1 required"); + + if (tracing) { + this.tracingExtents = new ArrayList<>(); + checkNotNull(actor, "An actor is required while tracing"); + } else { + this.tracingExtents = null; + } + + this.world = world; + this.actor = actor; + + if (world != null) { + EditSessionEvent event = new EditSessionEvent(world, actor, maxBlocks, null); + Watchdog watchdog = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getWatchdog(); + Extent extent; + + // These extents are ALWAYS used + extent = traceIfNeeded(sideEffectExtent = new SideEffectExtent(world)); + if (watchdog != null) { + // Reset watchdog before world placement + WatchdogTickingExtent watchdogExtent = new WatchdogTickingExtent(extent, watchdog); + extent = traceIfNeeded(watchdogExtent); + watchdogExtents.add(watchdogExtent); + } + extent = traceIfNeeded(survivalExtent = new SurvivalModeExtent(extent, world)); + extent = traceIfNeeded(new BiomeQuirkExtent(extent)); + extent = traceIfNeeded(new ChunkLoadingExtent(extent, world)); + extent = traceIfNeeded(new LastAccessExtentCache(extent)); + extent = traceIfNeeded(blockBagExtent = new BlockBagExtent(extent, blockBag)); + extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE); + this.bypassReorderHistory = traceIfNeeded(new DataValidatorExtent(extent, world)); + + // This extent can be skipped by calling rawSetBlock() + extent = traceIfNeeded(reorderExtent = new MultiStageReorder(extent, false)); + extent = traceIfNeeded(chunkBatchingExtent = new ChunkBatchingExtent(extent)); + extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER); + if (watchdog != null) { + // reset before buffering extents, since they may buffer all changes + // before the world-placement reset can happen, and still cause halts + WatchdogTickingExtent watchdogExtent = new WatchdogTickingExtent(extent, watchdog); + extent = traceIfNeeded(watchdogExtent); + watchdogExtents.add(watchdogExtent); + } + this.bypassHistory = traceIfNeeded(new DataValidatorExtent(extent, world)); + + // These extents can be skipped by calling smartSetBlock() + extent = traceIfNeeded(new ChangeSetExtent(extent, changeSet)); + extent = traceIfNeeded(maskingExtent = new MaskingExtent(extent, Masks.alwaysTrue())); + extent = traceIfNeeded(changeLimiter = new BlockChangeLimiter(extent, maxBlocks)); + extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY); + this.bypassNone = traceIfNeeded(new DataValidatorExtent(extent, world)); + } else { + Extent extent = new NullExtent(); + extent = traceIfNeeded(survivalExtent = new SurvivalModeExtent(extent, NullWorld.getInstance())); + extent = traceIfNeeded(blockBagExtent = new BlockBagExtent(extent, blockBag)); + extent = traceIfNeeded(reorderExtent = new MultiStageReorder(extent, false)); + extent = traceIfNeeded(maskingExtent = new MaskingExtent(extent, Masks.alwaysTrue())); + extent = traceIfNeeded(changeLimiter = new BlockChangeLimiter(extent, maxBlocks)); + this.bypassReorderHistory = extent; + this.bypassHistory = extent; + this.bypassNone = extent; + } + + setReorderMode(this.reorderMode); + } + + private Extent traceIfNeeded(Extent input) { + Extent output = input; + if (tracingExtents != null) { + TracingExtent newExtent = new TracingExtent(input); + output = newExtent; + tracingExtents.add(newExtent); + } + return output; + } + + private Extent wrapExtent(Extent extent, EventBus eventBus, EditSessionEvent event, Stage stage) { + // NB: the event does its own tracing + event = event.clone(stage); + event.setExtent(extent); + boolean tracing = tracingExtents != null; + event.setTracing(tracing); + eventBus.post(event); + if (tracing) { + tracingExtents.addAll(event.getTracingExtents()); + } + return event.getExtent(); + } + + // pkg private for TracedEditSession only, may later become public API + boolean commitRequired() { + if (reorderExtent != null && reorderExtent.commitRequired()) { + return true; + } + if (chunkBatchingExtent != null && chunkBatchingExtent.commitRequired()) { + return true; + } + if (sideEffectExtent != null && sideEffectExtent.commitRequired()) { + return true; + } + return false; + } + + /** + * Get the current list of active tracing extents. + */ + private List getActiveTracingExtents() { + if (tracingExtents == null) { + return ImmutableList.of(); + } + return tracingExtents.stream() + .filter(TracingExtent::isActive) + .collect(Collectors.toList()); + } + + /** + * Turns on specific features for a normal WorldEdit session, such as + * {@link #setBatchingChunks(boolean) + * chunk batching}. + */ + public void enableStandardMode() { + if (chunkBatchingExtent != null) { + setBatchingChunks(true); + } + } + + /** + * Sets the {@link ReorderMode} of this EditSession, and flushes the session. + * + * @param reorderMode The reorder mode + */ + public void setReorderMode(ReorderMode reorderMode) { + if (reorderMode == ReorderMode.FAST && sideEffectExtent == null) { + throw new IllegalArgumentException("An EditSession without a fast mode tried to use it for reordering!"); + } + if (reorderMode == ReorderMode.MULTI_STAGE && reorderExtent == null) { + throw new IllegalArgumentException("An EditSession without a reorder extent tried to use it for reordering!"); + } + if (commitRequired()) { + internalFlushSession(); + } + + this.reorderMode = reorderMode; + switch (reorderMode) { + case MULTI_STAGE: + if (sideEffectExtent != null) { + sideEffectExtent.setPostEditSimulationEnabled(false); + } + reorderExtent.setEnabled(true); + break; + case FAST: + sideEffectExtent.setPostEditSimulationEnabled(true); + if (reorderExtent != null) { + reorderExtent.setEnabled(false); + } + break; + case NONE: + if (sideEffectExtent != null) { + sideEffectExtent.setPostEditSimulationEnabled(false); + } + if (reorderExtent != null) { + reorderExtent.setEnabled(false); + } + break; + default: + break; + } + } + + /** + * Get the reorder mode. + * + * @return the reorder mode + */ + public ReorderMode getReorderMode() { + return reorderMode; + } + + /** + * Get the world. + * + * @return the world + */ + public World getWorld() { + return world; + } + + /** + * Get the underlying {@link ChangeSet}. + * + * @return the change set + */ + public ChangeSet getChangeSet() { + return changeSet; + } + + /** + * Get the maximum number of blocks that can be changed. -1 will be returned + * if it the limit disabled. + * + * @return the limit (>= 0) or -1 for no limit + */ + public int getBlockChangeLimit() { + return changeLimiter.getLimit(); + } + + /** + * Set the maximum number of blocks that can be changed. + * + * @param limit the limit (>= 0) or -1 for no limit + */ + public void setBlockChangeLimit(int limit) { + changeLimiter.setLimit(limit); + } + + /** + * Returns queue status. + * + * @return whether the queue is enabled + * @deprecated Use {@link EditSession#getReorderMode()} with MULTI_STAGE instead. + */ + @Deprecated + public boolean isQueueEnabled() { + return reorderMode == ReorderMode.MULTI_STAGE && reorderExtent.isEnabled(); + } + + /** + * Queue certain types of block for better reproduction of those blocks. + * + * @deprecated Use {@link EditSession#setReorderMode(ReorderMode)} with MULTI_STAGE instead. + */ + @Deprecated + public void enableQueue() { + setReorderMode(ReorderMode.MULTI_STAGE); + } + + /** + * Disable the queue. This will flush the session. + * + * @deprecated Use {@link EditSession#setReorderMode(ReorderMode)} with another mode instead. + */ + @Deprecated + public void disableQueue() { + if (isQueueEnabled()) { + internalFlushSession(); + } + setReorderMode(ReorderMode.NONE); + } + + /** + * Get the mask. + * + * @return mask, may be null + */ + public Mask getMask() { + return oldMask; + } + + /** + * Set a mask. + * + * @param mask mask or null + */ + public void setMask(Mask mask) { + this.oldMask = mask; + if (mask == null) { + maskingExtent.setMask(Masks.alwaysTrue()); + } else { + maskingExtent.setMask(mask); + } + } + + /** + * Get the {@link SurvivalModeExtent}. + * + * @return the survival simulation extent + */ + public SurvivalModeExtent getSurvivalExtent() { + return survivalExtent; + } + + /** + * Set whether fast mode is enabled. + * + *

Fast mode may skip lighting checks or adjacent block + * notification.

+ * + * @param enabled true to enable + */ + @Deprecated + public void setFastMode(boolean enabled) { + if (sideEffectExtent != null) { + sideEffectExtent.setSideEffectSet(enabled ? SideEffectSet.defaults() : SideEffectSet.none()); + } + } + + /** + * Set which block updates should occur. + * + * @param sideEffectSet side effects to enable + */ + public void setSideEffectApplier(SideEffectSet sideEffectSet) { + if (sideEffectExtent != null) { + sideEffectExtent.setSideEffectSet(sideEffectSet); + } + } + + /** + * Return fast mode status. + * + *

Fast mode may skip lighting checks or adjacent block + * notification.

+ * + * @return true if enabled + */ + @Deprecated + public boolean hasFastMode() { + return sideEffectExtent != null && this.sideEffectExtent.getSideEffectSet().doesApplyAny(); + } + + public SideEffectSet getSideEffectApplier() { + if (sideEffectExtent == null) { + return SideEffectSet.defaults(); + } + return sideEffectExtent.getSideEffectSet(); + } + + /** + * Get the {@link BlockBag} is used. + * + * @return a block bag or null + */ + public BlockBag getBlockBag() { + return blockBagExtent.getBlockBag(); + } + + /** + * Set a {@link BlockBag} to use. + * + * @param blockBag the block bag to set, or null to use none + */ + public void setBlockBag(BlockBag blockBag) { + blockBagExtent.setBlockBag(blockBag); + } + + /** + * Gets the list of missing blocks and clears the list for the next + * operation. + * + * @return a map of missing blocks + */ + public Map popMissingBlocks() { + return blockBagExtent.popMissing(); + } + + /** + * Returns chunk batching status. + * + * @return whether chunk batching is enabled + */ + public boolean isBatchingChunks() { + return chunkBatchingExtent != null && chunkBatchingExtent.isEnabled(); + } + + /** + * Enable or disable chunk batching. Disabling will flush the session. + * + * @param batchingChunks {@code true} to enable, {@code false} to disable + */ + public void setBatchingChunks(boolean batchingChunks) { + if (chunkBatchingExtent == null) { + if (batchingChunks) { + throw new UnsupportedOperationException("Chunk batching not supported by this session."); + } + return; + } + if (!batchingChunks && isBatchingChunks()) { + internalFlushSession(); + } + chunkBatchingExtent.setEnabled(batchingChunks); + } + + /** + * Disable all buffering extents. + * + * @see #setReorderMode(ReorderMode) + * @see #setBatchingChunks(boolean) + */ + public void disableBuffering() { + // We optimize here to avoid repeated calls to flushSession. + if (commitRequired()) { + internalFlushSession(); + } + setReorderMode(ReorderMode.NONE); + if (chunkBatchingExtent != null) { + chunkBatchingExtent.setEnabled(false); + } + } + + /** + * Check if this session will tick the watchdog. + * + * @return {@code true} if any watchdog extent is enabled + */ + public boolean isTickingWatchdog() { + return watchdogExtents.stream().anyMatch(WatchdogTickingExtent::isEnabled); + } + + /** + * Set all watchdog extents to the given mode. + */ + public void setTickingWatchdog(boolean active) { + for (WatchdogTickingExtent extent : watchdogExtents) { + extent.setEnabled(active); + } + } + + /** + * Get the number of blocks changed, including repeated block changes. + * + *

This number may not be accurate.

+ * + * @return the number of block changes + */ + public int getBlockChangeCount() { + return changeSet.size(); + } + + @Override + public boolean fullySupports3DBiomes() { + return bypassNone.fullySupports3DBiomes(); + } + + @Override + public BiomeType getBiome(BlockVector3 position) { + return bypassNone.getBiome(position); + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + return bypassNone.setBiome(position, biome); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return world.getBlock(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return world.getFullBlock(position); + } + + /** + * Returns the highest solid 'terrain' block. + * + * @param x the X coordinate + * @param z the Z coordinate + * @param minY minimal height + * @param maxY maximal height + * @return height of highest block found or 'minY' + */ + public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { + return getHighestTerrainBlock(x, z, minY, maxY, null); + } + + /** + * Returns the highest solid 'terrain' block. + * + * @param x the X coordinate + * @param z the Z coordinate + * @param minY minimal height + * @param maxY maximal height + * @param filter a mask of blocks to consider, or null to consider any solid (movement-blocking) block + * @return height of highest block found or 'minY' + */ + public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { + for (int y = maxY; y >= minY; --y) { + BlockVector3 pt = BlockVector3.at(x, y, z); + if (filter == null + ? getBlock(pt).getBlockType().getMaterial().isMovementBlocker() + : filter.test(pt)) { + return y; + } + } + + return minY; + } + + /** + * Set a block, bypassing both history and block re-ordering. + * + * @param position the position to set the block at + * @param block the block + * @param stage the level + * @return whether the block changed + * @throws WorldEditException thrown on a set error + */ + public > boolean setBlock(BlockVector3 position, B block, Stage stage) throws WorldEditException { + switch (stage) { + case BEFORE_HISTORY: + return bypassNone.setBlock(position, block); + case BEFORE_CHANGE: + return bypassHistory.setBlock(position, block); + case BEFORE_REORDER: + return bypassReorderHistory.setBlock(position, block); + default: + throw new RuntimeException("New enum entry added that is unhandled here"); + } + } + + /** + * Set a block, bypassing both history and block re-ordering. + * + * @param position the position to set the block at + * @param block the block + * @return whether the block changed + */ + public > boolean rawSetBlock(BlockVector3 position, B block) { + try { + return setBlock(position, block, Stage.BEFORE_CHANGE); + } catch (WorldEditException e) { + throw new RuntimeException("Unexpected exception", e); + } + } + + /** + * Set a block, bypassing history but still utilizing block re-ordering. + * + * @param position the position to set the block at + * @param block the block + * @return whether the block changed + */ + public > boolean smartSetBlock(BlockVector3 position, B block) { + try { + return setBlock(position, block, Stage.BEFORE_REORDER); + } catch (WorldEditException e) { + throw new RuntimeException("Unexpected exception", e); + } + } + + @Override + public > boolean setBlock(BlockVector3 position, B block) throws MaxChangedBlocksException { + try { + return setBlock(position, block, Stage.BEFORE_HISTORY); + } catch (MaxChangedBlocksException e) { + throw e; + } catch (WorldEditException e) { + throw new RuntimeException("Unexpected exception", e); + } + } + + /** + * Sets the block at a position, subject to both history and block re-ordering. + * + * @param position the position + * @param pattern a pattern to use + * @return Whether the block changed -- not entirely dependable + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public boolean setBlock(BlockVector3 position, Pattern pattern) throws MaxChangedBlocksException { + return setBlock(position, pattern.applyBlock(position)); + } + + /** + * Set blocks that are in a set of positions and return the number of times + * that the block set calls returned true. + * + * @param vset a set of positions + * @param pattern the pattern + * @return the number of changed blocks + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + private int setBlocks(Set vset, Pattern pattern) throws MaxChangedBlocksException { + int affected = 0; + for (BlockVector3 v : vset) { + affected += setBlock(v, pattern) ? 1 : 0; + } + return affected; + } + + @Override + @Nullable + public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { + return bypassNone.createEntity(location, entity); + } + + /** + * Restores all blocks to their initial state. + * + * @param editSession a new {@link EditSession} to perform the undo in + */ + public void undo(EditSession editSession) { + UndoContext context = new UndoContext(); + context.setExtent(editSession.bypassHistory); + Operations.completeBlindly(ChangeSetExecutor.createUndo(changeSet, context)); + editSession.internalFlushSession(); + } + + /** + * Sets to new state. + * + * @param editSession a new {@link EditSession} to perform the redo in + */ + public void redo(EditSession editSession) { + UndoContext context = new UndoContext(); + context.setExtent(editSession.bypassHistory); + Operations.completeBlindly(ChangeSetExecutor.createRedo(changeSet, context)); + editSession.internalFlushSession(); + } + + /** + * Get the number of changed blocks. + * + * @return the number of changes + */ + public int size() { + return getBlockChangeCount(); + } + + @Override + public BlockVector3 getMinimumPoint() { + return getWorld().getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return getWorld().getMaximumPoint(); + } + + @Override + public List getEntities(Region region) { + return bypassNone.getEntities(region); + } + + @Override + public List getEntities() { + return bypassNone.getEntities(); + } + + /** + * Closing an EditSession flushes its buffers to the world, and performs other + * cleanup tasks. + */ + @Override + public void close() { + internalFlushSession(); + dumpTracingInformation(); + } + + private void dumpTracingInformation() { + if (this.tracingExtents == null) { + return; + } + List tracingExtents = getActiveTracingExtents(); + assert actor != null; + if (tracingExtents.isEmpty()) { + actor.printError(TranslatableComponent.of("worldedit.trace.no-tracing-extents")); + return; + } + // find the common stacks + Set> stacks = new LinkedHashSet<>(); + Map, BlockVector3> stackToPosition = new HashMap<>(); + Set touchedLocations = Collections.newSetFromMap(BlockMap.create()); + for (TracingExtent tracingExtent : tracingExtents) { + touchedLocations.addAll(tracingExtent.getTouchedLocations()); + } + for (BlockVector3 loc : touchedLocations) { + List stack = tracingExtents.stream() + .filter(it -> it.getTouchedLocations().contains(loc)) + .collect(Collectors.toList()); + boolean anyFailed = stack.stream() + .anyMatch(it -> it.getFailedActions().containsKey(loc)); + if (anyFailed && stacks.add(stack)) { + stackToPosition.put(stack, loc); + } + } + stackToPosition.forEach((stack, position) -> { + // stack can never be empty, something has to have touched the position + TracingExtent failure = stack.get(0); + actor.printDebug(TranslatableComponent.builder("worldedit.trace.action-failed") + .args( + TextComponent.of(failure.getFailedActions().get(position).toString()), + TextComponent.of(position.toString()), + TextComponent.of(failure.getExtent().getClass().getName()) + ) + .build()); + }); + } + + /** + * Communicate to the EditSession that all block changes are complete, + * and that it should apply them to the world. + * + * @deprecated Replace with {@link #close()} for proper cleanup behavior. + */ + @Deprecated + public void flushSession() { + internalFlushSession(); + } + + private void internalFlushSession() { + Operations.completeBlindly(commit()); + } + + @Override + public @Nullable Operation commit() { + return bypassNone.commit(); + } + + /** + * Count the number of blocks of a list of types in a region. + * + * @param region the region + * @param searchBlocks the list of blocks to search + * @return the number of blocks that matched the block + */ + public int countBlocks(Region region, Set searchBlocks) { + BlockMask mask = new BlockMask(this, searchBlocks); + return countBlocks(region, mask); + } + + /** + * Count the number of blocks of a list of types in a region. + * + * @param region the region + * @param searchMask mask to match + * @return the number of blocks that matched the mask + */ + public int countBlocks(Region region, Mask searchMask) { + Counter count = new Counter(); + RegionMaskingFilter filter = new RegionMaskingFilter(searchMask, count); + RegionVisitor visitor = new RegionVisitor(region, filter); + Operations.completeBlindly(visitor); // We can't throw exceptions, nor do we expect any + return count.getCount(); + } + + /** + * Fills an area recursively in the X/Z directions. + * + * @param origin the location to start from + * @param block the block to fill with + * @param radius the radius of the spherical area to fill + * @param depth the maximum depth, starting from the origin + * @param recursive whether a breadth-first search should be performed + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public > int fillXZ(BlockVector3 origin, B block, double radius, int depth, boolean recursive) throws MaxChangedBlocksException { + return fillXZ(origin, (Pattern) block, radius, depth, recursive); + } + + /** + * Fills an area recursively in the X/Z directions. + * + * @param origin the origin to start the fill from + * @param pattern the pattern to fill with + * @param radius the radius of the spherical area to fill, with 0 as the smallest radius + * @param depth the maximum depth, starting from the origin, with 1 as the smallest depth + * @param recursive whether a breadth-first search should be performed + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int fillXZ(BlockVector3 origin, Pattern pattern, double radius, int depth, boolean recursive) throws MaxChangedBlocksException { + checkNotNull(origin); + checkNotNull(pattern); + checkArgument(radius >= 0, "radius >= 0"); + checkArgument(depth >= 1, "depth >= 1"); + + // Avoid int overflow (negative coordinate space allows for overflow back round to positive if the depth is large enough). + // Depth is always 1 or greater, thus the lower bound should always be <= origin y. + int lowerBound = origin.getBlockY() - depth + 1; + if (lowerBound > origin.getBlockY()) { + lowerBound = Integer.MIN_VALUE; + } + + MaskIntersection mask = new MaskIntersection( + new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), + new BoundedHeightMask( + Math.max(lowerBound, getWorld().getMinY()), + Math.min(getWorld().getMaxY(), origin.getBlockY())), + Masks.negate(new ExistingBlockMask(this))); + + // Want to replace blocks + BlockReplace replace = new BlockReplace(this, pattern); + + // Pick how we're going to visit blocks + RecursiveVisitor visitor; + if (recursive) { + visitor = new RecursiveVisitor(mask, replace); + } else { + visitor = new DownwardVisitor(mask, replace, origin.getBlockY()); + } + + // Start at the origin + visitor.visit(origin); + + // Execute + Operations.completeLegacy(visitor); + + return visitor.getAffected(); + } + + /** + * Remove a cuboid above the given position with a given apothem and a given height. + * + * @param position base position + * @param apothem an apothem of the cuboid (on the XZ plane), where the minimum is 1 + * @param height the height of the cuboid, where the minimum is 1 + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int removeAbove(BlockVector3 position, int apothem, int height) throws MaxChangedBlocksException { + checkNotNull(position); + checkArgument(apothem >= 1, "apothem >= 1"); + checkArgument(height >= 1, "height >= 1"); + + Region region = new CuboidRegion( + getWorld(), // Causes clamping of Y range + position.add(-apothem + 1, 0, -apothem + 1), + position.add(apothem - 1, height - 1, apothem - 1)); + return setBlocks(region, BlockTypes.AIR.getDefaultState()); + } + + /** + * Remove a cuboid below the given position with a given apothem and a given height. + * + * @param position base position + * @param apothem an apothem of the cuboid (on the XZ plane), where the minimum is 1 + * @param height the height of the cuboid, where the minimum is 1 + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int removeBelow(BlockVector3 position, int apothem, int height) throws MaxChangedBlocksException { + checkNotNull(position); + checkArgument(apothem >= 1, "apothem >= 1"); + checkArgument(height >= 1, "height >= 1"); + + Region region = new CuboidRegion( + getWorld(), // Causes clamping of Y range + position.add(-apothem + 1, 0, -apothem + 1), + position.add(apothem - 1, -height + 1, apothem - 1)); + return setBlocks(region, BlockTypes.AIR.getDefaultState()); + } + + /** + * Remove blocks of a certain type nearby a given position. + * + * @param position center position of cuboid + * @param mask the mask to match + * @param apothem an apothem of the cuboid, where the minimum is 1 + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int removeNear(BlockVector3 position, Mask mask, int apothem) throws MaxChangedBlocksException { + checkNotNull(position); + checkArgument(apothem >= 1, "apothem >= 1"); + + BlockVector3 adjustment = BlockVector3.ONE.multiply(apothem - 1); + Region region = new CuboidRegion( + getWorld(), // Causes clamping of Y range + position.add(adjustment.multiply(-1)), + position.add(adjustment)); + return replaceBlocks(region, mask, BlockTypes.AIR.getDefaultState()); + } + + /** + * Sets all the blocks inside a region to a given block type. + * + * @param region the region + * @param block the block + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public > int setBlocks(Region region, B block) throws MaxChangedBlocksException { + return setBlocks(region, (Pattern) block); + } + + /** + * Sets all the blocks inside a region to a given pattern. + * + * @param region the region + * @param pattern the pattern that provides the replacement block + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + + BlockReplace replace = new BlockReplace(this, pattern); + RegionVisitor visitor = new RegionVisitor(region, replace); + Operations.completeLegacy(visitor); + return visitor.getAffected(); + } + + /** + * Replaces all the blocks matching a given filter, within a given region, to a block + * returned by a given pattern. + * + * @param region the region to replace the blocks within + * @param filter a list of block types to match, or null to use {@link ExistingBlockMask} + * @param replacement the replacement block + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public > int replaceBlocks(Region region, Set filter, B replacement) throws MaxChangedBlocksException { + return replaceBlocks(region, filter, (Pattern) replacement); + } + + /** + * Replaces all the blocks matching a given filter, within a given region, to a block + * returned by a given pattern. + * + * @param region the region to replace the blocks within + * @param filter a list of block types to match, or null to use {@link ExistingBlockMask} + * @param pattern the pattern that provides the new blocks + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int replaceBlocks(Region region, Set filter, Pattern pattern) throws MaxChangedBlocksException { + Mask mask = filter == null ? new ExistingBlockMask(this) : new BlockMask(this, filter); + return replaceBlocks(region, mask, pattern); + } + + /** + * Replaces all the blocks matching a given mask, within a given region, to a block + * returned by a given pattern. + * + * @param region the region to replace the blocks within + * @param mask the mask that blocks must match + * @param pattern the pattern that provides the new blocks + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(mask); + checkNotNull(pattern); + + BlockReplace replace = new BlockReplace(this, pattern); + RegionMaskingFilter filter = new RegionMaskingFilter(mask, replace); + RegionVisitor visitor = new RegionVisitor(region, filter); + Operations.completeLegacy(visitor); + return visitor.getAffected(); + } + + /** + * Sets the blocks at the center of the given region to the given pattern. + * If the center sits between two blocks on a certain axis, then two blocks + * will be placed to mark the center. + * + * @param region the region to find the center of + * @param pattern the replacement pattern + * @return the number of blocks placed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int center(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + + Vector3 center = region.getCenter(); + Region centerRegion = new CuboidRegion( + getWorld(), // Causes clamping of Y range + BlockVector3.at(((int) center.getX()), ((int) center.getY()), ((int) center.getZ())), + BlockVector3.at( + MathUtils.roundHalfUp(center.getX()), + MathUtils.roundHalfUp(center.getY()), + MathUtils.roundHalfUp(center.getZ()))); + return setBlocks(centerRegion, pattern); + } + + /** + * Make the faces of the given region as if it was a {@link CuboidRegion}. + * + * @param region the region + * @param block the block to place + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + * @deprecated Use {@link EditSession#makeCuboidFaces(Region, Pattern)}. + */ + @Deprecated + public > int makeCuboidFaces(Region region, B block) throws MaxChangedBlocksException { + return makeCuboidFaces(region, (Pattern) block); + } + + /** + * Make the faces of the given region as if it was a {@link CuboidRegion}. + * + * @param region the region + * @param pattern the pattern to place + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeCuboidFaces(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + + CuboidRegion cuboid = CuboidRegion.makeCuboid(region); + Region faces = cuboid.getFaces(); + return setBlocks(faces, pattern); + } + + /** + * Make the faces of the given region. The method by which the faces are found + * may be inefficient, because there may not be an efficient implementation supported + * for that specific shape. + * + * @param region the region + * @param pattern the pattern to place + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeFaces(final Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + + if (region instanceof CuboidRegion) { + return makeCuboidFaces(region, pattern); + } else { + return new RegionShape(region).generate(this, pattern, true); + } + } + + + /** + * Make the walls (all faces but those parallel to the X-Z plane) of the given region + * as if it was a {@link CuboidRegion}. + * + * @param region the region + * @param block the block to place + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public > int makeCuboidWalls(Region region, B block) throws MaxChangedBlocksException { + return makeCuboidWalls(region, (Pattern) block); + } + + /** + * Make the walls (all faces but those parallel to the X-Z plane) of the given region + * as if it was a {@link CuboidRegion}. + * + * @param region the region + * @param pattern the pattern to place + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeCuboidWalls(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + + CuboidRegion cuboid = CuboidRegion.makeCuboid(region); + Region faces = cuboid.getWalls(); + return setBlocks(faces, pattern); + } + + /** + * Make the walls of the given region. The method by which the walls are found + * may be inefficient, because there may not be an efficient implementation supported + * for that specific shape. + * + * @param region the region + * @param pattern the pattern to place + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeWalls(final Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + + if (region instanceof CuboidRegion) { + return makeCuboidWalls(region, pattern); + } else { + final int minY = region.getMinimumPoint().getBlockY(); + final int maxY = region.getMaximumPoint().getBlockY(); + final ArbitraryShape shape = new RegionShape(region) { + @Override + protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { + if (y > maxY || y < minY) { + // Put holes into the floor and ceiling by telling ArbitraryShape that the shape goes on outside the region + return defaultMaterial; + } + + return super.getMaterial(x, y, z, defaultMaterial); + } + }; + return shape.generate(this, pattern, true); + } + } + + /** + * Places a layer of blocks on top of ground blocks in the given region + * (as if it were a cuboid). + * + * @param region the region + * @param block the placed block + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + * @deprecated Use {@link EditSession#overlayCuboidBlocks(Region, Pattern)}. + */ + @Deprecated + public > int overlayCuboidBlocks(Region region, B block) throws MaxChangedBlocksException { + checkNotNull(block); + + return overlayCuboidBlocks(region, (Pattern) block); + } + + /** + * Places a layer of blocks on top of ground blocks in the given region + * (as if it were a cuboid). + * + * @param region the region + * @param pattern the placed block pattern + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int overlayCuboidBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + + BlockReplace replace = new BlockReplace(this, pattern); + RegionOffset offset = new RegionOffset(BlockVector3.UNIT_Y, replace); + GroundFunction ground = new GroundFunction(new ExistingBlockMask(this), offset); + LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + Operations.completeLegacy(visitor); + return ground.getAffected(); + } + + /** + * Turns the first 3 layers into dirt/grass and the bottom layers + * into rock, like a natural Minecraft mountain. + * + * @param region the region to affect + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int naturalizeCuboidBlocks(Region region) throws MaxChangedBlocksException { + checkNotNull(region); + + Naturalizer naturalizer = new Naturalizer(this); + FlatRegion flatRegion = Regions.asFlatRegion(region); + LayerVisitor visitor = new LayerVisitor(flatRegion, minimumBlockY(region), maximumBlockY(region), naturalizer); + Operations.completeLegacy(visitor); + return naturalizer.getAffected(); + } + + /** + * Stack a cuboid region. For compatibility, entities are copied by biomes are not. + * Use {@link #stackCuboidRegion(Region, BlockVector3, int, boolean, boolean, Mask)} to fine tune. + * + * @param region the region to stack + * @param dir the direction to stack + * @param count the number of times to stack + * @param copyAir true to also copy air blocks + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int stackCuboidRegion(Region region, BlockVector3 dir, int count, boolean copyAir) throws MaxChangedBlocksException { + return stackCuboidRegion(region, dir, count, true, false, copyAir ? null : new ExistingBlockMask(this)); + } + + /** + * Stack a cuboid region. + * + * @param region the region to stack + * @param offset how far to move the contents each stack + * @param count the number of times to stack + * @param copyEntities true to copy entities + * @param copyBiomes true to copy biomes + * @param mask source mask for the operation (only matching blocks are copied) + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int stackCuboidRegion(Region region, BlockVector3 offset, int count, + boolean copyEntities, boolean copyBiomes, Mask mask) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(offset); + + BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); + try { + return stackRegionBlockUnits(region, offset.multiply(size), count, copyEntities, copyBiomes, mask); + } catch (RegionOperationException e) { + // Should never be able to happen + throw new AssertionError(e); + } + } + + /** + * Stack a region using block units. + * + * @param region the region to stack + * @param offset how far to move the contents each stack in block units + * @param count the number of times to stack + * @param copyEntities true to copy entities + * @param copyBiomes true to copy biomes + * @param mask source mask for the operation (only matching blocks are copied) + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + * @throws RegionOperationException thrown if the region operation is invalid + */ + public int stackRegionBlockUnits(Region region, BlockVector3 offset, int count, + boolean copyEntities, boolean copyBiomes, Mask mask) throws MaxChangedBlocksException, RegionOperationException { + checkNotNull(region); + checkNotNull(offset); + checkArgument(count >= 1, "count >= 1 required"); + + BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); + BlockVector3 offsetAbs = offset.abs(); + if (offsetAbs.getX() < size.getX() && offsetAbs.getY() < size.getY() && offsetAbs.getZ() < size.getZ()) { + throw new RegionOperationException(TranslatableComponent.of("worldedit.stack.intersecting-region")); + } + BlockVector3 to = region.getMinimumPoint(); + ForwardExtentCopy copy = new ForwardExtentCopy(this, region, this, to); + copy.setRepetitions(count); + copy.setTransform(new AffineTransform().translate(offset)); + copy.setCopyingEntities(copyEntities); + copy.setCopyingBiomes(copyBiomes); + if (mask != null) { + copy.setSourceMask(mask); + } + Operations.completeLegacy(copy); + return copy.getAffected(); + } + + /** + * Move the blocks in a region a certain direction. + * + * @param region the region to move + * @param offset the offset + * @param multiplier the number to multiply the offset by + * @param copyAir true to copy air blocks + * @param replacement the replacement pattern to fill in after moving, or null to use air + * @return number of blocks moved + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int moveRegion(Region region, BlockVector3 offset, int multiplier, boolean copyAir, Pattern replacement) throws MaxChangedBlocksException { + return moveRegion(region, offset, multiplier, true, false, copyAir ? new ExistingBlockMask(this) : null, replacement); + } + + /** + * Move the blocks in a region a certain direction. + * + * @param region the region to move + * @param offset the offset + * @param multiplier the number to multiply the offset by + * @param moveEntities true to move entities + * @param copyBiomes true to copy biomes (source biome is unchanged) + * @param mask source mask for the operation (only matching blocks are moved) + * @param replacement the replacement pattern to fill in after moving, or null to use air + * @return number of blocks moved + * @throws MaxChangedBlocksException thrown if too many blocks are changed + * @throws IllegalArgumentException thrown if the region is not a flat region, but copyBiomes is true + */ + public int moveRegion(Region region, BlockVector3 offset, int multiplier, + boolean moveEntities, boolean copyBiomes, Mask mask, Pattern replacement) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(offset); + checkArgument(multiplier >= 1, "multiplier >= 1 required"); + checkArgument(!copyBiomes || region instanceof FlatRegion, "can't copy biomes from non-flat region"); + + BlockVector3 to = region.getMinimumPoint(); + + // Remove the original blocks + Pattern pattern = replacement != null + ? replacement + : BlockTypes.AIR.getDefaultState(); + BlockReplace remove = new BlockReplace(this, pattern); + + // Copy to a buffer so we don't destroy our original before we can copy all the blocks from it + ForgetfulExtentBuffer buffer = new ForgetfulExtentBuffer(this, new RegionMask(region)); + ForwardExtentCopy copy = new ForwardExtentCopy(this, region, buffer, to); + copy.setTransform(new AffineTransform().translate(offset.multiply(multiplier))); + copy.setSourceFunction(remove); // Remove + + copy.setCopyingEntities(moveEntities); + copy.setRemovingEntities(moveEntities); + copy.setCopyingBiomes(copyBiomes); + + if (mask != null) { + copy.setSourceMask(mask); + } + + // Then we need to copy the buffer to the world + BlockReplace replace = new BlockReplace(this, buffer); + RegionVisitor visitor = new RegionVisitor(buffer.asRegion(), replace); + + OperationQueue operation = new OperationQueue(copy, visitor); + + if (copyBiomes) { + BiomeReplace biomeReplace = new BiomeReplace(this, buffer); + RegionVisitor biomeVisitor = new RegionVisitor(buffer.asRegion(), biomeReplace); + operation.offer(biomeVisitor); + } + + Operations.completeLegacy(operation); + + return copy.getAffected(); + } + + /** + * Move the blocks in a region a certain direction. + * + * @param region the region to move + * @param dir the direction + * @param distance the distance to move + * @param copyAir true to copy air blocks + * @param replacement the replacement pattern to fill in after moving, or null to use air + * @return number of blocks moved + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int moveCuboidRegion(Region region, BlockVector3 dir, int distance, boolean copyAir, Pattern replacement) throws MaxChangedBlocksException { + return moveRegion(region, dir, distance, copyAir, replacement); + } + + /** + * Drain nearby pools of water or lava. + * + * @param origin the origin to drain from, which will search a 3x3 area + * @param radius the radius of the removal, where a value should be 0 or greater + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int drainArea(BlockVector3 origin, double radius) throws MaxChangedBlocksException { + return drainArea(origin, radius, false); + } + + /** + * Drain nearby pools of water or lava, optionally removed waterlogged states from blocks. + * + * @param origin the origin to drain from, which will search a 3x3 area + * @param radius the radius of the removal, where a value should be 0 or greater + * @param waterlogged true to make waterlogged blocks non-waterlogged as well + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int drainArea(BlockVector3 origin, double radius, boolean waterlogged) throws MaxChangedBlocksException { + checkNotNull(origin); + checkArgument(radius >= 0, "radius >= 0 required"); + + Mask waterloggedMask = null; + if (waterlogged) { + Map stateMap = new HashMap<>(); + stateMap.put("waterlogged", "true"); + waterloggedMask = new BlockStateMask(this, stateMap, true); + } + MaskIntersection mask = new MaskIntersection( + new BoundedHeightMask(getWorld().getMinY(), getWorld().getMaxY()), + new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), + waterlogged ? new MaskUnion(getWorld().createLiquidMask(), waterloggedMask) + : getWorld().createLiquidMask()); + + BlockReplace replace; + if (waterlogged) { + replace = new BlockReplace(this, new WaterloggedRemover(this)); + } else { + replace = new BlockReplace(this, BlockTypes.AIR.getDefaultState()); + } + RecursiveVisitor visitor = new RecursiveVisitor(mask, replace); + + // Around the origin in a 3x3 block + for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) { + if (mask.test(position)) { + visitor.visit(position); + } + } + + Operations.completeLegacy(visitor); + + return visitor.getAffected(); + } + + /** + * Fix liquids so that they turn into stationary blocks and extend outward. + * + * @param origin the original position + * @param radius the radius to fix + * @param fluid the type of the fluid + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int fixLiquid(BlockVector3 origin, double radius, BlockType fluid) throws MaxChangedBlocksException { + checkNotNull(origin); + checkArgument(radius >= 0, "radius >= 0 required"); + + // Our origins can only be liquids + Mask liquidMask = new BlockTypeMask(this, fluid); + + // But we will also visit air blocks + MaskIntersection blockMask = new MaskUnion(liquidMask, Masks.negate(new ExistingBlockMask(this))); + + // There are boundaries that the routine needs to stay in + MaskIntersection mask = new MaskIntersection( + new BoundedHeightMask(getWorld().getMinY(), Math.min(origin.getBlockY(), getWorld().getMaxY())), + new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), + blockMask + ); + + BlockReplace replace = new BlockReplace(this, fluid.getDefaultState()); + NonRisingVisitor visitor = new NonRisingVisitor(mask, replace); + + // Around the origin in a 3x3 block + for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) { + if (liquidMask.test(position)) { + visitor.visit(position); + } + } + + Operations.completeLegacy(visitor); + + return visitor.getAffected(); + } + + /** + * Makes a cylinder. + * + * @param pos Center of the cylinder + * @param block The block pattern to use + * @param radius The cylinder's radius + * @param height The cylinder's up/down extent. If negative, extend downward. + * @param filled If false, only a shell will be generated. + * @return number of blocks changed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeCylinder(BlockVector3 pos, Pattern block, double radius, int height, boolean filled) throws MaxChangedBlocksException { + return makeCylinder(pos, block, radius, radius, height, filled); + } + + /** + * Makes a cylinder. + * + * @param pos Center of the cylinder + * @param block The block pattern to use + * @param radiusX The cylinder's largest north/south extent + * @param radiusZ The cylinder's largest east/west extent + * @param height The cylinder's up/down extent. If negative, extend downward. + * @param filled If false, only a shell will be generated. + * @return number of blocks changed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeCylinder(BlockVector3 pos, Pattern block, double radiusX, double radiusZ, int height, boolean filled) throws MaxChangedBlocksException { + int affected = 0; + + radiusX += 0.5; + radiusZ += 0.5; + + if (height == 0) { + return 0; + } else if (height < 0) { + height = -height; + pos = pos.subtract(0, height, 0); + } + + if (pos.getBlockY() < world.getMinY()) { + pos = pos.withY(world.getMinY()); + } else if (pos.getBlockY() + height - 1 > world.getMaxY()) { + height = world.getMaxY() - pos.getBlockY() + 1; + } + + final double invRadiusX = 1 / radiusX; + final double invRadiusZ = 1 / radiusZ; + + final int ceilRadiusX = (int) Math.ceil(radiusX); + final int ceilRadiusZ = (int) Math.ceil(radiusZ); + + double nextXn = 0; + forX: for (int x = 0; x <= ceilRadiusX; ++x) { + final double xn = nextXn; + nextXn = (x + 1) * invRadiusX; + double nextZn = 0; + forZ: for (int z = 0; z <= ceilRadiusZ; ++z) { + final double zn = nextZn; + nextZn = (z + 1) * invRadiusZ; + + double distanceSq = lengthSq(xn, zn); + if (distanceSq > 1) { + if (z == 0) { + break forX; + } + break forZ; + } + + if (!filled) { + if (lengthSq(nextXn, zn) <= 1 && lengthSq(xn, nextZn) <= 1) { + continue; + } + } + + for (int y = 0; y < height; ++y) { + if (setBlock(pos.add(x, y, z), block)) { + ++affected; + } + if (setBlock(pos.add(-x, y, z), block)) { + ++affected; + } + if (setBlock(pos.add(x, y, -z), block)) { + ++affected; + } + if (setBlock(pos.add(-x, y, -z), block)) { + ++affected; + } + } + } + } + + return affected; + } + + /** + * Makes a sphere. + * + * @param pos Center of the sphere or ellipsoid + * @param block The block pattern to use + * @param radius The sphere's radius + * @param filled If false, only a shell will be generated. + * @return number of blocks changed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeSphere(BlockVector3 pos, Pattern block, double radius, boolean filled) throws MaxChangedBlocksException { + return makeSphere(pos, block, radius, radius, radius, filled); + } + + /** + * Makes a sphere or ellipsoid. + * + * @param pos Center of the sphere or ellipsoid + * @param block The block pattern to use + * @param radiusX The sphere/ellipsoid's largest north/south extent + * @param radiusY The sphere/ellipsoid's largest up/down extent + * @param radiusZ The sphere/ellipsoid's largest east/west extent + * @param filled If false, only a shell will be generated. + * @return number of blocks changed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeSphere(BlockVector3 pos, Pattern block, double radiusX, double radiusY, double radiusZ, boolean filled) throws MaxChangedBlocksException { + int affected = 0; + + radiusX += 0.5; + radiusY += 0.5; + radiusZ += 0.5; + + final double invRadiusX = 1 / radiusX; + final double invRadiusY = 1 / radiusY; + final double invRadiusZ = 1 / radiusZ; + + final int ceilRadiusX = (int) Math.ceil(radiusX); + final int ceilRadiusY = (int) Math.ceil(radiusY); + final int ceilRadiusZ = (int) Math.ceil(radiusZ); + + double nextXn = 0; + forX: for (int x = 0; x <= ceilRadiusX; ++x) { + final double xn = nextXn; + nextXn = (x + 1) * invRadiusX; + double nextYn = 0; + forY: for (int y = 0; y <= ceilRadiusY; ++y) { + final double yn = nextYn; + nextYn = (y + 1) * invRadiusY; + double nextZn = 0; + forZ: for (int z = 0; z <= ceilRadiusZ; ++z) { + final double zn = nextZn; + nextZn = (z + 1) * invRadiusZ; + + double distanceSq = lengthSq(xn, yn, zn); + if (distanceSq > 1) { + if (z == 0) { + if (y == 0) { + break forX; + } + break forY; + } + break forZ; + } + + if (!filled) { + if (lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) { + continue; + } + } + + if (setBlock(pos.add(x, y, z), block)) { + ++affected; + } + if (setBlock(pos.add(-x, y, z), block)) { + ++affected; + } + if (setBlock(pos.add(x, -y, z), block)) { + ++affected; + } + if (setBlock(pos.add(x, y, -z), block)) { + ++affected; + } + if (setBlock(pos.add(-x, -y, z), block)) { + ++affected; + } + if (setBlock(pos.add(x, -y, -z), block)) { + ++affected; + } + if (setBlock(pos.add(-x, y, -z), block)) { + ++affected; + } + if (setBlock(pos.add(-x, -y, -z), block)) { + ++affected; + } + } + } + } + + return affected; + } + + /** + * Makes a pyramid. + * + * @param position a position + * @param block a block + * @param size size of pyramid + * @param filled true if filled + * @return number of blocks changed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makePyramid(BlockVector3 position, Pattern block, int size, boolean filled) throws MaxChangedBlocksException { + int affected = 0; + + int height = size; + + for (int y = 0; y <= height; ++y) { + size--; + for (int x = 0; x <= size; ++x) { + for (int z = 0; z <= size; ++z) { + + if ((filled && z <= size && x <= size) || z == size || x == size) { + + if (setBlock(position.add(x, y, z), block)) { + ++affected; + } + if (setBlock(position.add(-x, y, z), block)) { + ++affected; + } + if (setBlock(position.add(x, y, -z), block)) { + ++affected; + } + if (setBlock(position.add(-x, y, -z), block)) { + ++affected; + } + } + } + } + } + + return affected; + } + + /** + * Thaw blocks in a radius. + * + * @param position the position + * @param radius the radius + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + * @deprecated Use {@link #thaw(BlockVector3, double, int)}. + */ + @Deprecated + public int thaw(BlockVector3 position, double radius) + throws MaxChangedBlocksException { + return thaw(position, radius, + WorldEdit.getInstance().getConfiguration().defaultVerticalHeight); + } + + /** + * Thaw blocks in a cylinder. + * + * @param position the position + * @param radius the radius + * @param height the height (upwards and downwards) + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int thaw(BlockVector3 position, double radius, int height) + throws MaxChangedBlocksException { + int affected = 0; + double radiusSq = radius * radius; + + int ox = position.getBlockX(); + int oy = position.getBlockY(); + int oz = position.getBlockZ(); + + BlockState air = BlockTypes.AIR.getDefaultState(); + BlockState water = BlockTypes.WATER.getDefaultState(); + + int centerY = Math.max(getWorld().getMinY(), Math.min(getWorld().getMaxY(), oy)); + int minY = Math.max(getWorld().getMinY(), centerY - height); + int maxY = Math.min(getWorld().getMaxY(), centerY + height); + + int ceilRadius = (int) Math.ceil(radius); + for (int x = ox - ceilRadius; x <= ox + ceilRadius; ++x) { + for (int z = oz - ceilRadius; z <= oz + ceilRadius; ++z) { + if ((BlockVector3.at(x, oy, z)).distanceSq(position) > radiusSq) { + continue; + } + + for (int y = maxY; y > minY; --y) { + BlockVector3 pt = BlockVector3.at(x, y, z); + BlockType id = getBlock(pt).getBlockType(); + + if (id == BlockTypes.ICE) { + if (setBlock(pt, water)) { + ++affected; + } + } else if (id == BlockTypes.SNOW) { + if (setBlock(pt, air)) { + ++affected; + } + } else if (id.getMaterial().isAir()) { + continue; + } + + break; + } + } + } + + return affected; + } + + /** + * Make snow in a radius. + * + * @param position a position + * @param radius a radius + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + * @deprecated Use {@link #simulateSnow(BlockVector3, double, int)}. + */ + @Deprecated + public int simulateSnow(BlockVector3 position, double radius) throws MaxChangedBlocksException { + return simulateSnow(position, radius, + WorldEdit.getInstance().getConfiguration().defaultVerticalHeight); + } + + /** + * Make snow in a cylinder. + * + * @param position a position + * @param radius a radius + * @param height the height (upwards and downwards) + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int simulateSnow(BlockVector3 position, double radius, int height) + throws MaxChangedBlocksException { + + return simulateSnow(new CylinderRegion(position, Vector2.at(radius, radius), position.getBlockY(), height), false); + } + + + /** + * Make snow in a region. + * + * @param region the region to simulate snow in + * @param stack whether it should stack existing snow + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int simulateSnow(FlatRegion region, boolean stack) + throws MaxChangedBlocksException { + checkNotNull(region); + + SnowSimulator snowSimulator = new SnowSimulator(this, stack); + LayerVisitor layerVisitor = new LayerVisitor(region, region.getMinimumY(), region.getMaximumY(), snowSimulator); + Operations.completeLegacy(layerVisitor); + return snowSimulator.getAffected(); + } + + /** + * Make dirt green. + * + * @param position a position + * @param radius a radius + * @param onlyNormalDirt only affect normal dirt (all default properties) + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + * @deprecated Use {@link #green(BlockVector3, double, int, boolean)}. + */ + @Deprecated + public int green(BlockVector3 position, double radius, boolean onlyNormalDirt) + throws MaxChangedBlocksException { + return green(position, radius, + WorldEdit.getInstance().getConfiguration().defaultVerticalHeight, onlyNormalDirt); + } + + /** + * Make dirt green in a cylinder. + * + * @param position the position + * @param radius the radius + * @param height the height + * @param onlyNormalDirt only affect normal dirt (all default properties) + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int green(BlockVector3 position, double radius, int height, boolean onlyNormalDirt) + throws MaxChangedBlocksException { + int affected = 0; + final double radiusSq = radius * radius; + + final int ox = position.getBlockX(); + final int oy = position.getBlockY(); + final int oz = position.getBlockZ(); + + final BlockState grass = BlockTypes.GRASS_BLOCK.getDefaultState(); + + final int centerY = Math.max(getWorld().getMinY(), Math.min(getWorld().getMaxY(), oy)); + final int minY = Math.max(getWorld().getMinY(), centerY - height); + final int maxY = Math.min(getWorld().getMaxY(), centerY + height); + + final int ceilRadius = (int) Math.ceil(radius); + for (int x = ox - ceilRadius; x <= ox + ceilRadius; ++x) { + for (int z = oz - ceilRadius; z <= oz + ceilRadius; ++z) { + if ((BlockVector3.at(x, oy, z)).distanceSq(position) > radiusSq) { + continue; + } + + for (int y = maxY; y > minY; --y) { + final BlockVector3 pt = BlockVector3.at(x, y, z); + final BlockState block = getBlock(pt); + + if (block.getBlockType() == BlockTypes.DIRT + || (!onlyNormalDirt && block.getBlockType() == BlockTypes.COARSE_DIRT)) { + if (setBlock(pt, grass)) { + ++affected; + } + break; + } else if (block.getBlockType() == BlockTypes.WATER || block.getBlockType() == BlockTypes.LAVA) { + break; + } else if (block.getBlockType().getMaterial().isMovementBlocker()) { + break; + } + } + } + } + + return affected; + } + + /** + * Makes pumpkin patches randomly in an area around the given position. + * + * @param position the base position + * @param apothem the apothem of the (square) area + * @return number of patches created + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makePumpkinPatches(BlockVector3 position, int apothem) throws MaxChangedBlocksException { + // We want to generate pumpkins + GardenPatchGenerator generator = new GardenPatchGenerator(this); + generator.setPlant(GardenPatchGenerator.getPumpkinPattern()); + + // In a region of the given radius + FlatRegion region = new CuboidRegion( + getWorld(), // Causes clamping of Y range + position.add(-apothem, -5, -apothem), + position.add(apothem, 10, apothem)); + double density = 0.02; + + GroundFunction ground = new GroundFunction(new ExistingBlockMask(this), generator); + LayerVisitor visitor = new LayerVisitor(region, minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + Operations.completeLegacy(visitor); + return ground.getAffected(); + } + + /** + * Makes a forest. + * + * @param basePosition a position + * @param size a size + * @param density between 0 and 1, inclusive + * @param treeType the tree type + * @return number of trees created + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeForest(BlockVector3 basePosition, int size, double density, TreeGenerator.TreeType treeType) throws MaxChangedBlocksException { + return makeForest(CuboidRegion.fromCenter(basePosition, size), density, treeType); + } + + /** + * Makes a forest. + * + * @param region the region to generate trees in + * @param density between 0 and 1, inclusive + * @param treeType the tree type + * @return number of trees created + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeForest(Region region, double density, TreeGenerator.TreeType treeType) throws MaxChangedBlocksException { + ForestGenerator generator = new ForestGenerator(this, treeType); + GroundFunction ground = new GroundFunction(new ExistingBlockMask(this), generator); + LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + Operations.completeLegacy(visitor); + return ground.getAffected(); + } + + /** + * Get the block distribution inside a region. + * + * @param region a region + * @return the results + */ + public List> getBlockDistribution(Region region, boolean separateStates) { + BlockDistributionCounter count = new BlockDistributionCounter(this, separateStates); + RegionVisitor visitor = new RegionVisitor(region, count); + Operations.completeBlindly(visitor); + return count.getDistribution(); + } + + /** + * Generate a shape for the given expression. + * + * @param region the region to generate the shape in + * @param zero the coordinate origin for x/y/z variables + * @param unit the scale of the x/y/z/ variables + * @param pattern the default material to make the shape from + * @param expressionString the expression defining the shape + * @param hollow whether the shape should be hollow + * @return number of blocks changed + * @throws ExpressionException if there is a problem with the expression + * @throws MaxChangedBlocksException if the maximum block change limit is exceeded + */ + public int makeShape(final Region region, final Vector3 zero, final Vector3 unit, + final Pattern pattern, final String expressionString, final boolean hollow) + throws ExpressionException, MaxChangedBlocksException { + return makeShape(region, zero, unit, pattern, expressionString, hollow, WorldEdit.getInstance().getConfiguration().calculationTimeout); + } + + /** + * Generate a shape for the given expression. + * + * @param region the region to generate the shape in + * @param zero the coordinate origin for x/y/z variables + * @param unit the scale of the x/y/z/ variables + * @param pattern the default material to make the shape from + * @param expressionString the expression defining the shape + * @param hollow whether the shape should be hollow + * @param timeout the time, in milliseconds, to wait for each expression evaluation before halting it. -1 to disable + * @return number of blocks changed + * @throws ExpressionException if there is a problem with the expression + * @throws MaxChangedBlocksException if the maximum block change limit is exceeded + */ + public int makeShape(final Region region, final Vector3 zero, final Vector3 unit, + final Pattern pattern, final String expressionString, final boolean hollow, final int timeout) + throws ExpressionException, MaxChangedBlocksException { + final Expression expression = Expression.compile(expressionString, "x", "y", "z", "type", "data"); + expression.optimize(); + return makeShape(region, zero, unit, pattern, expression, hollow, timeout); + } + + /** + * Internal version of {@link EditSession#makeShape(Region, Vector3, Vector3, Pattern, String, boolean, int)}. + * + *

+ * The Expression class is subject to change. Expressions should be provided via the string overload. + *

+ */ + public int makeShape(final Region region, final Vector3 zero, final Vector3 unit, + final Pattern pattern, final Expression expression, final boolean hollow, final int timeout) + throws ExpressionException, MaxChangedBlocksException { + + expression.getSlots().getVariable("x") + .orElseThrow(IllegalStateException::new); + expression.getSlots().getVariable("y") + .orElseThrow(IllegalStateException::new); + expression.getSlots().getVariable("z") + .orElseThrow(IllegalStateException::new); + + final Variable typeVariable = expression.getSlots().getVariable("type") + .orElseThrow(IllegalStateException::new); + final Variable dataVariable = expression.getSlots().getVariable("data") + .orElseThrow(IllegalStateException::new); + + final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero); + expression.setEnvironment(environment); + + final int[] timedOut = {0}; + final ArbitraryShape shape = new ArbitraryShape(region) { + @Override + protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { + final Vector3 current = Vector3.at(x, y, z); + environment.setCurrentBlock(current); + final Vector3 scaled = current.subtract(zero).divide(unit); + + try { + int[] legacy = LegacyMapper.getInstance().getLegacyFromBlock(defaultMaterial.toImmutableState()); + int typeVar = 0; + int dataVar = 0; + if (legacy != null) { + typeVar = legacy[0]; + if (legacy.length > 1) { + dataVar = legacy[1]; + } + } + if (expression.evaluate(new double[]{scaled.getX(), scaled.getY(), scaled.getZ(), typeVar, dataVar}, timeout) <= 0) { + return null; + } + int newType = (int) typeVariable.getValue(); + int newData = (int) dataVariable.getValue(); + if (newType != typeVar || newData != dataVar) { + BlockState state = LegacyMapper.getInstance().getBlockFromLegacy(newType, newData); + return state == null ? defaultMaterial : state.toBaseBlock(); + } else { + return defaultMaterial; + } + } catch (ExpressionTimeoutException e) { + timedOut[0] = timedOut[0] + 1; + return null; + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + int changed = shape.generate(this, pattern, hollow); + if (timedOut[0] > 0) { + throw new ExpressionTimeoutException( + String.format("%d blocks changed. %d blocks took too long to evaluate (increase with //timeout).", + changed, timedOut[0])); + } + return changed; + } + + /** + * Deforms the region by a given expression. A deform provides a block's x, y, and z coordinates (possibly scaled) + * to an expression, and then sets the block to the block given by the resulting values of the variables, if they + * have changed. + * + * @param region the region to deform + * @param zero the origin of the coordinate system + * @param unit the scale of the coordinate system + * @param expressionString the expression to evaluate for each block + * + * @return number of blocks changed + * + * @throws ExpressionException thrown on invalid expression input + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int deformRegion(final Region region, final Vector3 zero, final Vector3 unit, final String expressionString) + throws ExpressionException, MaxChangedBlocksException { + return deformRegion(region, zero, unit, expressionString, WorldEdit.getInstance().getConfiguration().calculationTimeout); + } + + /** + * Deforms the region by a given expression. A deform provides a block's x, y, and z coordinates (possibly scaled) + * to an expression, and then sets the block to the block given by the resulting values of the variables, if they + * have changed. + * + * @param region the region to deform + * @param zero the origin of the coordinate system + * @param unit the scale of the coordinate system + * @param expressionString the expression to evaluate for each block + * @param timeout maximum time for the expression to evaluate for each block. -1 for unlimited. + * + * @return number of blocks changed + * + * @throws ExpressionException thrown on invalid expression input + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int deformRegion(final Region region, final Vector3 zero, final Vector3 unit, final String expressionString, + final int timeout) throws ExpressionException, MaxChangedBlocksException { + final Expression expression = Expression.compile(expressionString, "x", "y", "z"); + expression.optimize(); + return deformRegion(region, zero, unit, expression, timeout); + } + + /** + * Internal version of {@link EditSession#deformRegion(Region, Vector3, Vector3, String, int)}. + * + *

+ * The Expression class is subject to change. Expressions should be provided via the string overload. + *

+ */ + public int deformRegion(final Region region, final Vector3 zero, final Vector3 unit, final Expression expression, + final int timeout) throws ExpressionException, MaxChangedBlocksException { + final Variable x = expression.getSlots().getVariable("x") + .orElseThrow(IllegalStateException::new); + final Variable y = expression.getSlots().getVariable("y") + .orElseThrow(IllegalStateException::new); + final Variable z = expression.getSlots().getVariable("z") + .orElseThrow(IllegalStateException::new); + + final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero); + expression.setEnvironment(environment); + + final DoubleArrayList queue = new DoubleArrayList<>(false); + + for (BlockVector3 position : region) { + // offset, scale + final Vector3 scaled = position.toVector3().subtract(zero).divide(unit); + + // transform + expression.evaluate(new double[]{scaled.getX(), scaled.getY(), scaled.getZ()}, timeout); + + final BlockVector3 sourcePosition = environment.toWorld(x.getValue(), y.getValue(), z.getValue()); + + // read block from world + final BaseBlock material = world.getFullBlock(sourcePosition); + + // queue operation + queue.put(position, material); + } + + int affected = 0; + for (Map.Entry entry : queue) { + BlockVector3 position = entry.getKey(); + BaseBlock material = entry.getValue(); + + // set at new position + if (setBlock(position, material)) { + ++affected; + } + } + + return affected; + } + + /** + * Hollows out the region (Semi-well-defined for non-cuboid selections). + * + * @param region the region to hollow out. + * @param thickness the thickness of the shell to leave (manhattan distance) + * @param pattern The block pattern to use + * + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int hollowOutRegion(Region region, int thickness, Pattern pattern) throws MaxChangedBlocksException { + int affected = 0; + + final Set outside = new HashSet<>(); + + final BlockVector3 min = region.getMinimumPoint(); + final BlockVector3 max = region.getMaximumPoint(); + + final int minX = min.getBlockX(); + final int minY = min.getBlockY(); + final int minZ = min.getBlockZ(); + final int maxX = max.getBlockX(); + final int maxY = max.getBlockY(); + final int maxZ = max.getBlockZ(); + + for (int x = minX; x <= maxX; ++x) { + for (int y = minY; y <= maxY; ++y) { + recurseHollow(region, BlockVector3.at(x, y, minZ), outside); + recurseHollow(region, BlockVector3.at(x, y, maxZ), outside); + } + } + + for (int y = minY; y <= maxY; ++y) { + for (int z = minZ; z <= maxZ; ++z) { + recurseHollow(region, BlockVector3.at(minX, y, z), outside); + recurseHollow(region, BlockVector3.at(maxX, y, z), outside); + } + } + + for (int z = minZ; z <= maxZ; ++z) { + for (int x = minX; x <= maxX; ++x) { + recurseHollow(region, BlockVector3.at(x, minY, z), outside); + recurseHollow(region, BlockVector3.at(x, maxY, z), outside); + } + } + + for (int i = 1; i < thickness; ++i) { + final Set newOutside = new HashSet<>(); + outer: for (BlockVector3 position : region) { + for (BlockVector3 recurseDirection : recurseDirections) { + BlockVector3 neighbor = position.add(recurseDirection); + + if (outside.contains(neighbor)) { + newOutside.add(position); + continue outer; + } + } + } + + outside.addAll(newOutside); + } + + outer: for (BlockVector3 position : region) { + for (BlockVector3 recurseDirection : recurseDirections) { + BlockVector3 neighbor = position.add(recurseDirection); + + if (outside.contains(neighbor)) { + continue outer; + } + } + + if (setBlock(position, pattern.applyBlock(position))) { + ++affected; + } + } + + return affected; + } + + /** + * Draws a line (out of blocks) between two vectors. + * + * @param pattern The block pattern used to draw the line. + * @param pos1 One of the points that define the line. + * @param pos2 The other point that defines the line. + * @param radius The radius (thickness) of the line. + * @param filled If false, only a shell will be generated. + * + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + * + * @see #drawLine(Pattern, List, double, boolean) + */ + public int drawLine(Pattern pattern, BlockVector3 pos1, BlockVector3 pos2, double radius, boolean filled) + throws MaxChangedBlocksException { + return drawLine(pattern, ImmutableList.of(pos1, pos2), radius, filled); + } + + /** + * Draws a line (out of blocks) between two or more vectors. + * + * @param pattern The block pattern used to draw the line. + * @param vectors the list of vectors to draw the line between + * @param radius The radius (thickness) of the line. + * @param filled If false, only a shell will be generated. + * + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int drawLine(Pattern pattern, List vectors, double radius, boolean filled) + throws MaxChangedBlocksException { + + Set vset = new HashSet<>(); + + for (int i = 0; vectors.size() != 0 && i < vectors.size() - 1; i++) { + BlockVector3 pos1 = vectors.get(i); + BlockVector3 pos2 = vectors.get(i + 1); + + int x1 = pos1.getBlockX(); + int y1 = pos1.getBlockY(); + int z1 = pos1.getBlockZ(); + int x2 = pos2.getBlockX(); + int y2 = pos2.getBlockY(); + int z2 = pos2.getBlockZ(); + int tipx = x1; + int tipy = y1; + int tipz = z1; + int dx = Math.abs(x2 - x1); + int dy = Math.abs(y2 - y1); + int dz = Math.abs(z2 - z1); + + if (dx + dy + dz == 0) { + vset.add(BlockVector3.at(tipx, tipy, tipz)); + continue; + } + + int dMax = Math.max(Math.max(dx, dy), dz); + if (dMax == dx) { + for (int domstep = 0; domstep <= dx; domstep++) { + tipx = x1 + domstep * (x2 - x1 > 0 ? 1 : -1); + tipy = (int) Math.round(y1 + domstep * ((double) dy) / ((double) dx) * (y2 - y1 > 0 ? 1 : -1)); + tipz = (int) Math.round(z1 + domstep * ((double) dz) / ((double) dx) * (z2 - z1 > 0 ? 1 : -1)); + + vset.add(BlockVector3.at(tipx, tipy, tipz)); + } + } else if (dMax == dy) { + for (int domstep = 0; domstep <= dy; domstep++) { + tipy = y1 + domstep * (y2 - y1 > 0 ? 1 : -1); + tipx = (int) Math.round(x1 + domstep * ((double) dx) / ((double) dy) * (x2 - x1 > 0 ? 1 : -1)); + tipz = (int) Math.round(z1 + domstep * ((double) dz) / ((double) dy) * (z2 - z1 > 0 ? 1 : -1)); + + vset.add(BlockVector3.at(tipx, tipy, tipz)); + } + } else /* if (dMax == dz) */ { + for (int domstep = 0; domstep <= dz; domstep++) { + tipz = z1 + domstep * (z2 - z1 > 0 ? 1 : -1); + tipy = (int) Math.round(y1 + domstep * ((double) dy) / ((double) dz) * (y2 - y1 > 0 ? 1 : -1)); + tipx = (int) Math.round(x1 + domstep * ((double) dx) / ((double) dz) * (x2 - x1 > 0 ? 1 : -1)); + + vset.add(BlockVector3.at(tipx, tipy, tipz)); + } + } + } + + vset = getBallooned(vset, radius); + if (!filled) { + vset = getHollowed(vset); + } + return setBlocks(vset, pattern); + } + + /** + * Draws a spline (out of blocks) between specified vectors. + * + * @param pattern The block pattern used to draw the spline. + * @param nodevectors The list of vectors to draw through. + * @param tension The tension of every node. + * @param bias The bias of every node. + * @param continuity The continuity of every node. + * @param quality The quality of the spline. Must be greater than 0. + * @param radius The radius (thickness) of the spline. + * @param filled If false, only a shell will be generated. + * + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int drawSpline(Pattern pattern, List nodevectors, double tension, double bias, + double continuity, double quality, double radius, boolean filled) + throws MaxChangedBlocksException { + + Set vset = new HashSet<>(); + List nodes = new ArrayList<>(nodevectors.size()); + + Interpolation interpol = new KochanekBartelsInterpolation(); + + for (BlockVector3 nodevector : nodevectors) { + Node n = new Node(nodevector.toVector3()); + n.setTension(tension); + n.setBias(bias); + n.setContinuity(continuity); + nodes.add(n); + } + + interpol.setNodes(nodes); + double splinelength = interpol.arcLength(0, 1); + for (double loop = 0; loop <= 1; loop += 1D / splinelength / quality) { + Vector3 tipv = interpol.getPosition(loop); + + vset.add(tipv.toBlockPoint()); + } + + vset = getBallooned(vset, radius); + if (!filled) { + vset = getHollowed(vset); + } + return setBlocks(vset, pattern); + } + + private static double hypot(double... pars) { + double sum = 0; + for (double d : pars) { + sum += Math.pow(d, 2); + } + return Math.sqrt(sum); + } + + private static Set getBallooned(Set vset, double radius) { + Set returnset = new HashSet<>(); + int ceilrad = (int) Math.ceil(radius); + + for (BlockVector3 v : vset) { + int tipx = v.getBlockX(); + int tipy = v.getBlockY(); + int tipz = v.getBlockZ(); + + for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) { + for (int loopy = tipy - ceilrad; loopy <= tipy + ceilrad; loopy++) { + for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) { + if (hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= radius) { + returnset.add(BlockVector3.at(loopx, loopy, loopz)); + } + } + } + } + } + return returnset; + } + + private static Set getHollowed(Set vset) { + Set returnset = new HashSet<>(); + for (BlockVector3 v : vset) { + double x = v.getX(); + double y = v.getY(); + double z = v.getZ(); + if (!(vset.contains(BlockVector3.at(x + 1, y, z)) + && vset.contains(BlockVector3.at(x - 1, y, z)) + && vset.contains(BlockVector3.at(x, y + 1, z)) + && vset.contains(BlockVector3.at(x, y - 1, z)) + && vset.contains(BlockVector3.at(x, y, z + 1)) + && vset.contains(BlockVector3.at(x, y, z - 1)))) { + returnset.add(v); + } + } + return returnset; + } + + private void recurseHollow(Region region, BlockVector3 origin, Set outside) { + final LinkedList queue = new LinkedList<>(); + queue.addLast(origin); + + while (!queue.isEmpty()) { + final BlockVector3 current = queue.removeFirst(); + final BlockState block = getBlock(current); + if (block.getBlockType().getMaterial().isMovementBlocker()) { + continue; + } + + if (!outside.add(current)) { + continue; + } + + if (!region.contains(current)) { + continue; + } + + for (BlockVector3 recurseDirection : recurseDirections) { + queue.addLast(current.add(recurseDirection)); + } + } + } + + public int makeBiomeShape(final Region region, final Vector3 zero, final Vector3 unit, final BiomeType biomeType, + final String expressionString, final boolean hollow) throws ExpressionException { + return makeBiomeShape(region, zero, unit, biomeType, expressionString, hollow, WorldEdit.getInstance().getConfiguration().calculationTimeout); + } + + public int makeBiomeShape(final Region region, final Vector3 zero, final Vector3 unit, final BiomeType biomeType, + final String expressionString, final boolean hollow, final int timeout) throws ExpressionException { + + final Expression expression = Expression.compile(expressionString, "x", "y", "z"); + expression.optimize(); + + final EditSession editSession = this; + final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(editSession, unit, zero); + expression.setEnvironment(environment); + + AtomicInteger timedOut = new AtomicInteger(); + final ArbitraryBiomeShape shape = new ArbitraryBiomeShape(region) { + @Override + protected BiomeType getBiome(int x, int y, int z, BiomeType defaultBiomeType) { + final Vector3 current = Vector3.at(x, y, z); + environment.setCurrentBlock(current); + final Vector3 scaled = current.subtract(zero).divide(unit); + + try { + if (expression.evaluate(new double[]{scaled.getX(), scaled.getY(), scaled.getZ()}, timeout) <= 0) { + return null; + } + + // TODO: Allow biome setting via a script variable (needs BiomeType<->int mapping) + return defaultBiomeType; + } catch (ExpressionTimeoutException e) { + timedOut.getAndIncrement(); + return null; + } catch (Exception e) { + LOGGER.warn("Failed to create shape", e); + return null; + } + } + }; + int changed = shape.generate(this, biomeType, hollow); + if (timedOut.get() > 0) { + throw new ExpressionTimeoutException( + String.format("%d biomes changed. %d biomes took too long to evaluate (increase time with //timeout)", + changed, timedOut.get())); + } + return changed; + } + + private static final BlockVector3[] recurseDirections = { + Direction.NORTH.toBlockVector(), + Direction.EAST.toBlockVector(), + Direction.SOUTH.toBlockVector(), + Direction.WEST.toBlockVector(), + Direction.UP.toBlockVector(), + Direction.DOWN.toBlockVector(), + }; + + private static double lengthSq(double x, double y, double z) { + return (x * x) + (y * y) + (z * z); + } + + private static double lengthSq(double x, double z) { + return (x * x) + (z * z); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java b/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java new file mode 100644 index 0000000..57b7686 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java @@ -0,0 +1,145 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import com.google.common.base.Preconditions; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.util.eventbus.EventBus; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; + +/** + * A builder-style factory for {@link EditSession EditSessions}. + */ +public final class EditSessionBuilder { + + private final EventBus eventBus; + private @Nullable World world; + private int maxBlocks = -1; + private @Nullable Actor actor; + private @Nullable BlockBag blockBag; + private boolean tracing; + + EditSessionBuilder(EventBus eventBus) { + this.eventBus = eventBus; + } + + public @Nullable World getWorld() { + return world; + } + + /** + * Set the world for the {@link EditSession}. + * + * @param world the world + * @return this builder + */ + public EditSessionBuilder world(@Nullable World world) { + this.world = world; + return this; + } + + public int getMaxBlocks() { + return maxBlocks; + } + + /** + * Set the maximum blocks to change for the {@link EditSession}. + * + * @param maxBlocks the maximum blocks to change + * @return this builder + */ + public EditSessionBuilder maxBlocks(int maxBlocks) { + this.maxBlocks = maxBlocks; + return this; + } + + public @Nullable Actor getActor() { + return actor; + } + + /** + * Set the actor who owns the {@link EditSession}. + * + * @param actor the actor + * @return this builder + */ + public EditSessionBuilder actor(@Nullable Actor actor) { + this.actor = actor; + return this; + } + + public @Nullable BlockBag getBlockBag() { + return blockBag; + } + + /** + * Set the block bag for the {@link EditSession}. + * + * @param blockBag the block bag + * @return this builder + */ + public EditSessionBuilder blockBag(@Nullable BlockBag blockBag) { + this.blockBag = blockBag; + return this; + } + + /** + * Check if tracing is enabled. + * + * Internal use only. + */ + public boolean isTracing() { + return tracing; + } + + /** + * Set tracing enabled/disabled. + * + * Internal use only. + */ + public EditSessionBuilder tracing(boolean tracing) { + this.tracing = tracing; + return this; + } + + // Extended methods + public EditSessionBuilder locatableActor(A locatable) { + Extent extent = locatable.getExtent(); + Preconditions.checkArgument(extent instanceof World, "%s is not located in a World", locatable); + return world(((World) extent)).actor(locatable); + } + + /** + * Build the {@link EditSession} using properties described in this builder. + * + * @return the new EditSession + */ + public EditSession build() { + if (WorldEdit.getInstance().getConfiguration().traceUnflushedSessions) { + return new TracedEditSession(eventBus, world, maxBlocks, blockBag, actor, tracing); + } + return new EditSession(eventBus, world, maxBlocks, blockBag, actor, tracing); + } +} diff --git a/src/main/java/com/sk89q/worldedit/EditSessionFactory.java b/src/main/java/com/sk89q/worldedit/EditSessionFactory.java new file mode 100644 index 0000000..286897c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/EditSessionFactory.java @@ -0,0 +1,176 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.world.World; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates new {@link EditSession}s. To get an instance of this factory, + * use {@link WorldEdit#getEditSessionFactory()}. + * + *

It is no longer possible to replace the instance of this in WorldEdit + * with a custom one. Use {@link EditSessionEvent} to override + * the creation of {@link EditSession}s.

+ * + * @deprecated Using the ever-extending factory methods is deprecated. Replace with {@link EditSessionBuilder}, + * which in most cases will be as simple as calling {@code builder.world(world).build()}. + */ +@Deprecated +public class EditSessionFactory { + + /** + * Construct an edit session with a maximum number of blocks. + * + * @param world the world + * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit + * @return an instance + */ + public EditSession getEditSession(World world, int maxBlocks) { + + // ============ READ ME ============ + + // This method is actually implemented if you call WorldEdit.getEditSessionFactory() + // as it returns an instance of EditSessionFactoryImpl seen below. + + // Previously, other plugins would create their own EditSessionFactory and extend ours and + // then use it to return custom EditSessions so the plugin could log block changes, etc. + // However, that method only allows one plugin to hook into WorldEdit at a time, + // so now we recommend catching the EditSessionEvent and hooking into our + // new(er) Extent framework. + + throw new RuntimeException("Method needs to be implemented"); + } + + /** + * Construct an edit session with a maximum number of blocks. + * + * @param world the world + * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit + * @param actor the actor that the {@link EditSession} is for + * @return an instance + */ + public EditSession getEditSession(World world, int maxBlocks, Actor actor) { + + // ============ READ ME ============ + + // This method is actually implemented if you call WorldEdit.getEditSessionFactory() + // as it returns an instance of EditSessionFactoryImpl seen below. + + // Previously, other plugins would create their own EditSessionFactory and extend ours and + // then use it to return custom EditSessions so the plugin could log block changes, etc. + // However, that method only allows one plugin to hook into WorldEdit at a time, + // so now we recommend catching the EditSessionEvent and hooking into our + // new(er) Extent framework. + + throw new RuntimeException("Method needs to be implemented"); + } + + /** + * Construct an edit session with a maximum number of blocks and a block bag. + * + * @param world the world + * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit + * @param blockBag an optional {@link BlockBag} to use, otherwise null + * @return an instance + */ + public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag) { + + // ============ READ ME ============ + + // This method is actually implemented if you call WorldEdit.getEditSessionFactory() + // as it returns an instance of EditSessionFactoryImpl seen below. + + // Previously, other plugins would create their own EditSessionFactory and extend ours and + // then use it to return custom EditSessions so the plugin could log block changes, etc. + // However, that method only allows one plugin to hook into WorldEdit at a time, + // so now we recommend catching the EditSessionEvent and hooking into our + // new(er) Extent framework. + + throw new RuntimeException("Method needs to be implemented"); + } + + /** + * Construct an edit session with a maximum number of blocks and a block bag. + * + * @param world the world + * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit + * @param blockBag an optional {@link BlockBag} to use, otherwise null + * @param actor the actor that the {@link EditSession} is for + * @return an instance + */ + public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Actor actor) { + + // ============ READ ME ============ + + // This method is actually implemented if you call WorldEdit.getEditSessionFactory() + // as it returns an instance of EditSessionFactoryImpl seen below. + + // Previously, other plugins would create their own EditSessionFactory and extend ours and + // then use it to return custom EditSessions so the plugin could log block changes, etc. + // However, that method only allows one plugin to hook into WorldEdit at a time, + // so now we recommend catching the EditSessionEvent and hooking into our + // new(er) Extent framework. + + throw new RuntimeException("Method needs to be implemented"); + } + + /** + * Internal factory for {@link EditSession}s. + */ + static final class EditSessionFactoryImpl extends EditSessionFactory { + + /** + * Create a new factory. + */ + EditSessionFactoryImpl() { + } + + @Override + public EditSession getEditSession(World world, int maxBlocks) { + return getEditSession(world, maxBlocks, null, null); + } + + @Override + public EditSession getEditSession(World world, int maxBlocks, Actor actor) { + return getEditSession(world, maxBlocks, null, actor); + } + + @Override + public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag) { + return getEditSession(world, maxBlocks, blockBag, null); + } + + @Override + public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Actor actor) { + return WorldEdit.getInstance().newEditSessionBuilder() + .world(world) + .maxBlocks(maxBlocks) + .blockBag(blockBag) + .actor(actor) + .build(); + } + + } +} diff --git a/src/main/java/com/sk89q/worldedit/EmptyClipboardException.java b/src/main/java/com/sk89q/worldedit/EmptyClipboardException.java new file mode 100644 index 0000000..b6dfabb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/EmptyClipboardException.java @@ -0,0 +1,27 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +/** + * Thrown when there is no clipboard set. + */ +public class EmptyClipboardException extends WorldEditException { + +} diff --git a/src/main/java/com/sk89q/worldedit/IncompleteRegionException.java b/src/main/java/com/sk89q/worldedit/IncompleteRegionException.java new file mode 100644 index 0000000..3861b71 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/IncompleteRegionException.java @@ -0,0 +1,27 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +/** + * Raised when a region is not fully defined. + */ +public class IncompleteRegionException extends WorldEditException { + +} diff --git a/src/main/java/com/sk89q/worldedit/InvalidItemException.java b/src/main/java/com/sk89q/worldedit/InvalidItemException.java new file mode 100644 index 0000000..86b8122 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/InvalidItemException.java @@ -0,0 +1,32 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +/** + * Thrown when an invalid item is specified. + */ +@Deprecated +public class InvalidItemException extends DisallowedItemException { + + public InvalidItemException(String type, String message) { + super(type, message); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/src/main/java/com/sk89q/worldedit/LocalConfiguration.java new file mode 100644 index 0000000..0df25a1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -0,0 +1,240 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import com.google.common.collect.Lists; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.util.formatting.component.TextUtils; +import com.sk89q.worldedit.util.io.file.ArchiveNioSupports; +import com.sk89q.worldedit.util.logging.LogFormat; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.registry.LegacyMapper; +import com.sk89q.worldedit.world.snapshot.SnapshotRepository; +import com.sk89q.worldedit.world.snapshot.experimental.SnapshotDatabase; +import com.sk89q.worldedit.world.snapshot.experimental.fs.FileSystemSnapshotDatabase; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; + +/** + * Represents WorldEdit's configuration. + */ +public abstract class LocalConfiguration { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + public boolean profile = false; + public boolean traceUnflushedSessions = false; + public Set disallowedBlocks = new HashSet<>(); + public int defaultChangeLimit = -1; + public int maxChangeLimit = -1; + public int defaultVerticalHeight = 256; + public int defaultMaxPolygonalPoints = -1; + public int maxPolygonalPoints = 20; + public int defaultMaxPolyhedronPoints = -1; + public int maxPolyhedronPoints = 20; + public String shellSaveType = ""; + public boolean snapshotsConfigured = false; + public SnapshotRepository snapshotRepo = null; + public SnapshotDatabase snapshotDatabase = null; + public int maxRadius = -1; + public int maxSuperPickaxeSize = 5; + public int maxBrushRadius = 6; + public boolean logCommands = false; + public String logFile = ""; + public String logFormat = LogFormat.DEFAULT_FORMAT; + public boolean registerHelp = true; // unused + public String wandItem = "minecraft:wooden_axe"; + public boolean superPickaxeDrop = true; + public boolean superPickaxeManyDrop = true; + public boolean useInventory = false; + public boolean useInventoryOverride = false; + public boolean useInventoryCreativeOverride = false; + public boolean navigationUseGlass = true; + public String navigationWand = "minecraft:compass"; + public int navigationWandMaxDistance = 50; + public int scriptTimeout = 3000; + public int calculationTimeout = 100; + public int maxCalculationTimeout = 300; + public Set allowedDataCycleBlocks = new HashSet<>(); + public String saveDir = "schematics"; + public String scriptsDir = "craftscripts"; + public boolean showHelpInfo = true; // unused + public int butcherDefaultRadius = -1; + public int butcherMaxRadius = -1; + public boolean allowSymlinks = false; + public boolean serverSideCUI = true; + public boolean extendedYLimit = false; + public boolean commandBlockSupport = false; + public String defaultLocaleName = "default"; + public Locale defaultLocale = Locale.getDefault(); + + protected String[] getDefaultDisallowedBlocks() { + List blockTypes = Lists.newArrayList( + BlockTypes.OAK_SAPLING, + BlockTypes.JUNGLE_SAPLING, + BlockTypes.DARK_OAK_SAPLING, + BlockTypes.SPRUCE_SAPLING, + BlockTypes.BIRCH_SAPLING, + BlockTypes.ACACIA_SAPLING, + BlockTypes.BLACK_BED, + BlockTypes.BLUE_BED, + BlockTypes.BROWN_BED, + BlockTypes.CYAN_BED, + BlockTypes.GRAY_BED, + BlockTypes.GREEN_BED, + BlockTypes.LIGHT_BLUE_BED, + BlockTypes.LIGHT_GRAY_BED, + BlockTypes.LIME_BED, + BlockTypes.MAGENTA_BED, + BlockTypes.ORANGE_BED, + BlockTypes.PINK_BED, + BlockTypes.PURPLE_BED, + BlockTypes.RED_BED, + BlockTypes.WHITE_BED, + BlockTypes.YELLOW_BED, + BlockTypes.POWERED_RAIL, + BlockTypes.DETECTOR_RAIL, + BlockTypes.GRASS, + BlockTypes.DEAD_BUSH, + BlockTypes.MOVING_PISTON, + BlockTypes.PISTON_HEAD, + BlockTypes.SUNFLOWER, + BlockTypes.ROSE_BUSH, + BlockTypes.DANDELION, + BlockTypes.POPPY, + BlockTypes.BROWN_MUSHROOM, + BlockTypes.RED_MUSHROOM, + BlockTypes.TNT, + BlockTypes.TORCH, + BlockTypes.FIRE, + BlockTypes.REDSTONE_WIRE, + BlockTypes.WHEAT, + BlockTypes.POTATOES, + BlockTypes.CARROTS, + BlockTypes.MELON_STEM, + BlockTypes.PUMPKIN_STEM, + BlockTypes.BEETROOTS, + BlockTypes.RAIL, + BlockTypes.LEVER, + BlockTypes.REDSTONE_TORCH, + BlockTypes.REDSTONE_WALL_TORCH, + BlockTypes.REPEATER, + BlockTypes.COMPARATOR, + BlockTypes.STONE_BUTTON, + BlockTypes.BIRCH_BUTTON, + BlockTypes.ACACIA_BUTTON, + BlockTypes.DARK_OAK_BUTTON, + BlockTypes.JUNGLE_BUTTON, + BlockTypes.OAK_BUTTON, + BlockTypes.SPRUCE_BUTTON, + BlockTypes.CACTUS, + BlockTypes.SUGAR_CANE, + // ores and stuff + BlockTypes.BEDROCK + ); + return blockTypes.stream().filter(Objects::nonNull).map(BlockType::getId).toArray(String[]::new); + } + + /** + * Load the configuration. + */ + public abstract void load(); + + /** + * Get the working directory to work from. + * + * @return a working directory + * @deprecated Use {@link LocalConfiguration#getWorkingDirectoryPath()} + */ + @Deprecated + public File getWorkingDirectory() { + return getWorkingDirectoryPath().toFile(); + } + + /** + * Get the working directory to work from. + * + * @return a working directory + */ + public Path getWorkingDirectoryPath() { + return Paths.get("."); + } + + public void initializeSnapshotConfiguration(String directory, boolean experimental) { + // Reset for reload + snapshotRepo = null; + snapshotDatabase = null; + snapshotsConfigured = false; + if (!directory.isEmpty()) { + if (experimental) { + try { + snapshotDatabase = FileSystemSnapshotDatabase.maybeCreate( + Paths.get(directory), + ArchiveNioSupports.combined() + ); + snapshotsConfigured = true; + } catch (IOException e) { + LOGGER.warn("Failed to open snapshotDatabase", e); + } + } else { + snapshotRepo = new SnapshotRepository(directory); + snapshotsConfigured = true; + } + } + } + + public String convertLegacyItem(String legacy) { + String item = legacy; + try { + String[] splitter = item.split(":", 2); + int id = 0; + byte data = 0; + if (splitter.length == 1) { + id = Integer.parseInt(item); + } else { + id = Integer.parseInt(splitter[0]); + data = Byte.parseByte(splitter[1]); + } + item = LegacyMapper.getInstance().getItemFromLegacy(id, data).getId(); + } catch (Throwable ignored) { + } + + return item; + } + + public void setDefaultLocaleName(String localeName) { + this.defaultLocaleName = localeName; + if (localeName.equals("default")) { + this.defaultLocale = Locale.getDefault(); + } else { + this.defaultLocale = TextUtils.getLocaleByMinecraftTag(localeName); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/LocalSession.java b/src/main/java/com/sk89q/worldedit/LocalSession.java new file mode 100644 index 0000000..ec889e8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -0,0 +1,1208 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import com.sk89q.jchronic.Chronic; +import com.sk89q.jchronic.Options; +import com.sk89q.jchronic.utils.Span; +import com.sk89q.jchronic.utils.Time; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.command.tool.BlockTool; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.command.tool.InvalidToolBindException; +import com.sk89q.worldedit.command.tool.NavigationWand; +import com.sk89q.worldedit.command.tool.SelectionWand; +import com.sk89q.worldedit.command.tool.SinglePickaxe; +import com.sk89q.worldedit.command.tool.Tool; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; +import com.sk89q.worldedit.internal.cui.ServerCUIHandler; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelectorType; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.util.SideEffectSet; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; +import com.sk89q.worldedit.world.snapshot.experimental.Snapshot; + +import java.time.ZoneId; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.TimeZone; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Stores session information. + */ +public class LocalSession { + + private static final transient int CUI_VERSION_UNINITIALIZED = -1; + public static transient int MAX_HISTORY_SIZE = 15; + + // Non-session related fields + private transient LocalConfiguration config; + private final transient AtomicBoolean dirty = new AtomicBoolean(); + + // Single-connection lifetime fields + private transient int failedCuiAttempts = 0; + private transient boolean hasCUISupport = false; + private transient int cuiVersion = CUI_VERSION_UNINITIALIZED; + + // Session related + private transient RegionSelector selector = new CuboidRegionSelector(); + private transient boolean placeAtPos1 = false; + private final transient LinkedList history = new LinkedList<>(); + private transient int historyPointer = 0; + private transient ClipboardHolder clipboard; + private transient boolean superPickaxe = false; + private transient BlockTool pickaxeMode = new SinglePickaxe(); + private final transient Map tools = new HashMap<>(); + private transient int maxBlocksChanged = -1; + private transient int maxTimeoutTime; + private transient boolean useInventory; + private transient com.sk89q.worldedit.world.snapshot.Snapshot snapshot; + private transient Snapshot snapshotExperimental; + private transient SideEffectSet sideEffectSet = SideEffectSet.defaults(); + private transient Mask mask; + private transient ZoneId timezone = ZoneId.systemDefault(); + private transient BlockVector3 cuiTemporaryBlock; + private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE; + private transient List> lastDistribution; + private transient World worldOverride; + private transient boolean tickingWatchdog = true; + private transient boolean hasBeenToldVersion; + private transient boolean tracingActions; + + // Saved properties + private String lastScript; + private RegionSelectorType defaultSelector; + private boolean useServerCUI = false; // Save this to not annoy players. + private String wandItem; + private Boolean wandItemDefault; + private String navWandItem; + private Boolean navWandItemDefault; + + /** + * Construct the object. + * + *

{@link #setConfiguration(LocalConfiguration)} should be called + * later with configuration.

+ */ + public LocalSession() { + } + + /** + * Construct the object. + * + * @param config the configuration + */ + public LocalSession(@Nullable LocalConfiguration config) { + this.config = config; + } + + /** + * Set the configuration. + * + * @param config the configuration + */ + public void setConfiguration(LocalConfiguration config) { + checkNotNull(config); + this.config = config; + } + + /** + * Called on post load of the session from persistent storage. + */ + public void postLoad() { + if (defaultSelector != null) { + this.selector = defaultSelector.createSelector(); + } + } + + /** + * Get whether this session is "dirty" and has changes that needs to + * be committed. + * + * @return true if dirty + */ + public boolean isDirty() { + return dirty.get(); + } + + /** + * Set this session as dirty. + */ + private void setDirty() { + dirty.set(true); + } + + /** + * Get whether this session is "dirty" and has changes that needs to + * be committed, and reset it to {@code false}. + * + * @return true if the dirty value was {@code true} + */ + public boolean compareAndResetDirty() { + return dirty.compareAndSet(true, false); + } + + /** + * Get the session's timezone. + * + * @return the timezone + */ + public ZoneId getTimeZone() { + return timezone; + } + + /** + * Set the session's timezone. + * + * @param timezone the user's timezone + */ + public void setTimezone(ZoneId timezone) { + checkNotNull(timezone); + this.timezone = timezone; + } + + /** + * Clear history. + */ + public void clearHistory() { + history.clear(); + historyPointer = 0; + } + + /** + * Remember an edit session for the undo history. If the history maximum + * size is reached, old edit sessions will be discarded. + * + * @param editSession the edit session + */ + public void remember(EditSession editSession) { + checkNotNull(editSession); + + // Don't store anything if no changes were made + if (editSession.size() == 0) { + return; + } + + // Destroy any sessions after this undo point + while (historyPointer < history.size()) { + history.remove(historyPointer); + } + history.add(editSession); + while (history.size() > MAX_HISTORY_SIZE) { + history.remove(0); + } + historyPointer = history.size(); + } + + /** + * Performs an undo. + * + * @param newBlockBag a new block bag + * @param actor the actor + * @return whether anything was undone + */ + public EditSession undo(@Nullable BlockBag newBlockBag, Actor actor) { + checkNotNull(actor); + --historyPointer; + if (historyPointer >= 0) { + EditSession editSession = history.get(historyPointer); + try (EditSession newEditSession = + WorldEdit.getInstance().newEditSessionBuilder() + .world(editSession.getWorld()).blockBag(newBlockBag).actor(actor) + .build()) { + prepareEditingExtents(newEditSession, actor); + editSession.undo(newEditSession); + } + return editSession; + } else { + historyPointer = 0; + return null; + } + } + + /** + * Performs a redo. + * + * @param newBlockBag a new block bag + * @param actor the actor + * @return whether anything was redone + */ + public EditSession redo(@Nullable BlockBag newBlockBag, Actor actor) { + checkNotNull(actor); + if (historyPointer < history.size()) { + EditSession editSession = history.get(historyPointer); + try (EditSession newEditSession = + WorldEdit.getInstance().newEditSessionBuilder() + .world(editSession.getWorld()).blockBag(newBlockBag).actor(actor) + .build()) { + prepareEditingExtents(newEditSession, actor); + editSession.redo(newEditSession); + } + ++historyPointer; + return editSession; + } + + return null; + } + + public boolean hasWorldOverride() { + return this.worldOverride != null; + } + + @Nullable + public World getWorldOverride() { + return this.worldOverride; + } + + public void setWorldOverride(@Nullable World worldOverride) { + this.worldOverride = worldOverride; + } + + public boolean isTickingWatchdog() { + return tickingWatchdog; + } + + public void setTickingWatchdog(boolean tickingWatchdog) { + this.tickingWatchdog = tickingWatchdog; + } + + public boolean isTracingActions() { + return tracingActions; + } + + public void setTracingActions(boolean tracingActions) { + this.tracingActions = tracingActions; + } + + /** + * Get the default region selector. + * + * @return the default region selector + */ + public RegionSelectorType getDefaultRegionSelector() { + return defaultSelector; + } + + /** + * Set the default region selector. + * + * @param defaultSelector the default region selector + */ + public void setDefaultRegionSelector(RegionSelectorType defaultSelector) { + checkNotNull(defaultSelector); + this.defaultSelector = defaultSelector; + setDirty(); + } + + /** + * Get the region selector for defining the selection. If the selection + * was defined for a different world, the old selection will be discarded. + * + * @param world the world + * @return position the position + */ + public RegionSelector getRegionSelector(World world) { + checkNotNull(world); + if (selector.getWorld() == null || !selector.getWorld().equals(world)) { + selector.setWorld(world); + selector.clear(); + if (hasWorldOverride() && !world.equals(getWorldOverride())) { + setWorldOverride(null); + } + } + return selector; + } + + /** + * Set the region selector. + * + * @param world the world + * @param selector the selector + */ + public void setRegionSelector(World world, RegionSelector selector) { + checkNotNull(world); + checkNotNull(selector); + selector.setWorld(world); + this.selector = selector; + if (hasWorldOverride() && !world.equals(getWorldOverride())) { + setWorldOverride(null); + } + } + + /** + * Returns true if the region is fully defined for the specified world. + * + * @param world the world + * @return true if a region selection is defined + */ + public boolean isSelectionDefined(World world) { + checkNotNull(world); + if (selector.getIncompleteRegion().getWorld() == null || !selector.getIncompleteRegion().getWorld().equals(world)) { + return false; + } + return selector.isDefined(); + } + + /** + * Get the selection region. If you change the region, you should + * call learnRegionChanges(). If the selection is not fully defined, + * the {@code IncompleteRegionException} exception will be thrown. + * + *

Note that this method will return a region in the current selection world, + * which is not guaranteed to be the player's world or even the current world + * override. If you require a specific world, use the + * {@link LocalSession#getSelection(World)} overload instead. + * + * @return the selected region + * @throws IncompleteRegionException if the region is not fully defined + */ + public Region getSelection() throws IncompleteRegionException { + return getSelection(getSelectionWorld()); + } + + /** + * Get the selection region. If you change the region, you should + * call learnRegionChanges(). If the selection is defined in + * a different world, or the selection isn't fully defined, + * the {@code IncompleteRegionException} exception will be thrown. + * + * @param world the world + * @return a region + * @throws IncompleteRegionException if no region is selected, or the provided world is null + */ + public Region getSelection(@Nullable World world) throws IncompleteRegionException { + if (world == null || selector.getIncompleteRegion().getWorld() == null + || !selector.getIncompleteRegion().getWorld().equals(world)) { + throw new IncompleteRegionException(); + } + return selector.getRegion(); + } + + /** + * Get the selection world. + * + * @return the the world of the selection + */ + @Nullable + public World getSelectionWorld() { + return selector.getIncompleteRegion().getWorld(); + } + + /** + * Gets the clipboard. + * + * @return clipboard + * @throws EmptyClipboardException thrown if no clipboard is set + */ + public ClipboardHolder getClipboard() throws EmptyClipboardException { + if (clipboard == null) { + throw new EmptyClipboardException(); + } + return clipboard; + } + + /** + * Sets the clipboard. + * + *

Pass {@code null} to clear the clipboard.

+ * + * @param clipboard the clipboard, or null if the clipboard is to be cleared + */ + public void setClipboard(@Nullable ClipboardHolder clipboard) { + this.clipboard = clipboard; + } + + /** + * Check if tool control is enabled. + * + * @return true always - see deprecation notice + * @deprecated The wand is now a tool that can be bound/unbound. + */ + @Deprecated + public boolean isToolControlEnabled() { + return true; + } + + /** + * Set if tool control is enabled. + * + * @param toolControl unused - see deprecation notice + * @deprecated The wand is now a tool that can be bound/unbound. + */ + @Deprecated + public void setToolControl(boolean toolControl) { + } + + /** + * Get the maximum number of blocks that can be changed in an edit session. + * + * @return block change limit + */ + public int getBlockChangeLimit() { + return maxBlocksChanged; + } + + /** + * Set the maximum number of blocks that can be changed. + * + * @param maxBlocksChanged the maximum number of blocks changed + */ + public void setBlockChangeLimit(int maxBlocksChanged) { + this.maxBlocksChanged = maxBlocksChanged; + } + + /** + * Get the maximum time allowed for certain executions to run before cancelling them, such as expressions. + * + * @return timeout time, in milliseconds + */ + public int getTimeout() { + return maxTimeoutTime; + } + + /** + * Set the maximum number of blocks that can be changed. + * + * @param timeout the time, in milliseconds, to limit certain executions to, or -1 to disable + */ + public void setTimeout(int timeout) { + this.maxTimeoutTime = timeout; + } + + /** + * Checks whether the super pick axe is enabled. + * + * @return status + */ + public boolean hasSuperPickAxe() { + return superPickaxe; + } + + /** + * Enable super pick axe. + */ + public void enableSuperPickAxe() { + superPickaxe = true; + } + + /** + * Disable super pick axe. + */ + public void disableSuperPickAxe() { + superPickaxe = false; + } + + /** + * Toggle the super pick axe. + * + * @return whether the super pick axe is now enabled + */ + public boolean toggleSuperPickAxe() { + superPickaxe = !superPickaxe; + return superPickaxe; + } + + /** + * Get the position use for commands that take a center point + * (i.e. //forestgen, etc.). + * + * @param actor the actor + * @return the position to use + * @throws IncompleteRegionException thrown if a region is not fully selected + */ + public BlockVector3 getPlacementPosition(Actor actor) throws IncompleteRegionException { + checkNotNull(actor); + if (!placeAtPos1) { + if (actor instanceof Locatable) { + return ((Locatable) actor).getBlockLocation().toVector().toBlockPoint(); + } else { + throw new IncompleteRegionException(); + } + } + + return selector.getPrimaryPosition(); + } + + public void setPlaceAtPos1(boolean placeAtPos1) { + this.placeAtPos1 = placeAtPos1; + } + + public boolean isPlaceAtPos1() { + return placeAtPos1; + } + + /** + * Toggle placement position. + * + * @return whether "place at position 1" is now enabled + */ + public boolean togglePlacementPosition() { + placeAtPos1 = !placeAtPos1; + return placeAtPos1; + } + + /** + * Get a block bag for a player. + * + * @param player the player to get the block bag for + * @return a block bag + */ + @Nullable + public BlockBag getBlockBag(Player player) { + checkNotNull(player); + if (!useInventory) { + return null; + } + return player.getInventoryBlockBag(); + } + + /** + * Get the legacy snapshot that has been selected. + * + * @return the legacy snapshot + */ + @Nullable + public com.sk89q.worldedit.world.snapshot.Snapshot getSnapshot() { + return snapshot; + } + + /** + * Select a legacy snapshot. + * + * @param snapshot a legacy snapshot + */ + public void setSnapshot(@Nullable com.sk89q.worldedit.world.snapshot.Snapshot snapshot) { + this.snapshot = snapshot; + } + + /** + * Get the snapshot that has been selected. + * + * @return the snapshot + */ + public @Nullable Snapshot getSnapshotExperimental() { + return snapshotExperimental; + } + + /** + * Select a snapshot. + * + * @param snapshotExperimental a snapshot + */ + public void setSnapshotExperimental(@Nullable Snapshot snapshotExperimental) { + this.snapshotExperimental = snapshotExperimental; + } + + /** + * Get the assigned block tool. + * + * @return the super pickaxe tool mode + */ + public BlockTool getSuperPickaxe() { + return pickaxeMode; + } + + /** + * Set the super pick axe tool. + * + * @param tool the tool to set + */ + public void setSuperPickaxe(BlockTool tool) { + checkNotNull(tool); + this.pickaxeMode = tool; + } + + /** + * Get the tool assigned to the item. + * + * @param item the item type + * @return the tool, which may be {@code null} + */ + @Nullable + public Tool getTool(ItemType item) { + return tools.get(item); + } + + /** + * Get the brush tool assigned to the item. If there is no tool assigned + * or the tool is not assigned, the slot will be replaced with the + * brush tool. + * + * @param item the item type + * @return the tool, or {@code null} + * @throws InvalidToolBindException if the item can't be bound to that item + */ + public BrushTool getBrushTool(ItemType item) throws InvalidToolBindException { + Tool tool = getTool(item); + + if (!(tool instanceof BrushTool)) { + tool = new BrushTool("worldedit.brush.sphere"); + setTool(item, tool); + } + + return (BrushTool) tool; + } + + /** + * Set the tool. + * + * @param item the item type + * @param tool the tool to set, which can be {@code null} + * @throws InvalidToolBindException if the item can't be bound to that item + */ + public void setTool(ItemType item, @Nullable Tool tool) throws InvalidToolBindException { + if (item.hasBlockType()) { + throw new InvalidToolBindException(item, TranslatableComponent.of("worldedit.tool.error.item-only")); + } + if (tool instanceof SelectionWand) { + setSingleItemTool(id -> { + this.wandItem = id; + this.wandItemDefault = id.equals(config.wandItem); + }, this.wandItem, item); + } else if (tool instanceof NavigationWand) { + setSingleItemTool(id -> { + this.navWandItem = id; + this.navWandItemDefault = id.equals(config.navigationWand); + }, this.navWandItem, item); + } else if (tool == null) { + // Check if un-setting sel/nav + String id = item.getId(); + if (id.equals(this.wandItem)) { + this.wandItem = null; + setDirty(); + } else if (id.equals(this.navWandItem)) { + this.navWandItem = null; + setDirty(); + } + } + + this.tools.put(item, tool); + } + + private void setSingleItemTool(Consumer setter, @Nullable String itemId, ItemType newItem) { + if (itemId != null) { + ItemType item = ItemTypes.get(itemId); + if (item != null) { + this.tools.remove(item); + } + } + setter.accept(newItem.getId()); + setDirty(); + } + + /** + * Returns whether inventory usage is enabled for this session. + * + * @return if inventory is being used + */ + public boolean isUsingInventory() { + return useInventory; + } + + /** + * Set the state of inventory usage. + * + * @param useInventory if inventory is to be used + */ + public void setUseInventory(boolean useInventory) { + this.useInventory = useInventory; + } + + /** + * Get the last script used. + * + * @return the last script's name + */ + @Nullable + public String getLastScript() { + return lastScript; + } + + /** + * Set the last script used. + * + * @param lastScript the last script's name + */ + public void setLastScript(@Nullable String lastScript) { + this.lastScript = lastScript; + setDirty(); + } + + /** + * Tell the player the WorldEdit version. + * + * @param actor the actor + */ + public void tellVersion(Actor actor) { + if (hasBeenToldVersion) { + return; + } + hasBeenToldVersion = true; + actor.sendAnnouncements(); + } + + public boolean shouldUseServerCUI() { + return this.useServerCUI; + } + + public void setUseServerCUI(boolean useServerCUI) { + this.useServerCUI = useServerCUI; + setDirty(); + } + + /** + * Update server-side WorldEdit CUI. + * + * @param actor The player + */ + public void updateServerCUI(Actor actor) { + if (!actor.isPlayer()) { + return; // This is for players only. + } + + if (!config.serverSideCUI) { + return; // Disabled in config. + } + + Player player = (Player) actor; + + if (!useServerCUI || hasCUISupport) { + if (cuiTemporaryBlock != null) { + player.sendFakeBlock(cuiTemporaryBlock, null); + cuiTemporaryBlock = null; + } + return; // If it's not enabled, ignore this. + } + + BaseBlock block = ServerCUIHandler.createStructureBlock(player); + if (block != null) { + // If it's null, we don't need to do anything. The old was already removed. + Map tags = block.getNbtData().getValue(); + BlockVector3 tempCuiTemporaryBlock = BlockVector3.at( + ((IntTag) tags.get("x")).getValue(), + ((IntTag) tags.get("y")).getValue(), + ((IntTag) tags.get("z")).getValue() + ); + if (cuiTemporaryBlock != null && !tempCuiTemporaryBlock.equals(cuiTemporaryBlock)) { + // Update the existing block if it's the same location + player.sendFakeBlock(cuiTemporaryBlock, null); + } + cuiTemporaryBlock = tempCuiTemporaryBlock; + player.sendFakeBlock(cuiTemporaryBlock, block); + } else if (cuiTemporaryBlock != null) { + // Remove the old block + player.sendFakeBlock(cuiTemporaryBlock, null); + cuiTemporaryBlock = null; + } + } + + /** + * Dispatch a CUI event but only if the actor has CUI support. + * + * @param actor the actor + * @param event the event + */ + public void dispatchCUIEvent(Actor actor, CUIEvent event) { + checkNotNull(actor); + checkNotNull(event); + + if (hasCUISupport) { + actor.dispatchCUIEvent(event); + } else if (useServerCUI) { + updateServerCUI(actor); + } + } + + /** + * Dispatch the initial setup CUI messages. + * + * @param actor the actor + */ + public void dispatchCUISetup(Actor actor) { + if (selector != null) { + dispatchCUISelection(actor); + } + } + + /** + * Send the selection information. + * + * @param actor the actor + */ + public void dispatchCUISelection(Actor actor) { + checkNotNull(actor); + + if (!hasCUISupport && useServerCUI) { + updateServerCUI(actor); + return; + } + + if (selector instanceof CUIRegion) { + CUIRegion tempSel = (CUIRegion) selector; + + if (tempSel.getProtocolVersion() > cuiVersion) { + actor.dispatchCUIEvent(new SelectionShapeEvent(tempSel.getLegacyTypeID())); + tempSel.describeLegacyCUI(this, actor); + } else { + actor.dispatchCUIEvent(new SelectionShapeEvent(tempSel.getTypeID())); + tempSel.describeCUI(this, actor); + } + + } + } + + /** + * Describe the selection to the CUI actor. + * + * @param actor the actor + */ + public void describeCUI(Actor actor) { + checkNotNull(actor); + + if (!hasCUISupport) { + return; + } + + if (selector instanceof CUIRegion) { + CUIRegion tempSel = (CUIRegion) selector; + + if (tempSel.getProtocolVersion() > cuiVersion) { + tempSel.describeLegacyCUI(this, actor); + } else { + tempSel.describeCUI(this, actor); + } + + } + } + + /** + * Handle a CUI initialization message. + * + * @param text the message + */ + public void handleCUIInitializationMessage(String text, Actor actor) { + checkNotNull(text); + if (this.hasCUISupport) { + // WECUI is a bit aggressive about re-initializing itself + // the last attempt to touch handshakes didn't go well, so this will do... for now + dispatchCUISelection(actor); + return; + } else if (this.failedCuiAttempts > 3) { + return; + } + + String[] split = text.split("\\|", 2); + if (split.length > 1 && split[0].equalsIgnoreCase("v")) { // enough fields and right message + if (split[1].length() > 4) { + this.failedCuiAttempts++; + return; + } + + int version; + try { + version = Integer.parseInt(split[1]); + } catch (NumberFormatException e) { + WorldEdit.logger.warn("Error while reading CUI init message: " + e.getMessage()); + this.failedCuiAttempts++; + return; + } + setCUISupport(true); + setCUIVersion(version); + dispatchCUISelection(actor); + } + } + + /** + * Gets the status of CUI support. + * + * @return true if CUI is enabled + */ + public boolean hasCUISupport() { + return hasCUISupport; + } + + /** + * Sets the status of CUI support. + * + * @param support true if CUI is enabled + */ + public void setCUISupport(boolean support) { + hasCUISupport = support; + } + + /** + * Gets the client's CUI protocol version. + * + * @return the CUI version + */ + public int getCUIVersion() { + return cuiVersion; + } + + /** + * Sets the client's CUI protocol version. + * + * @param cuiVersion the CUI version + */ + public void setCUIVersion(int cuiVersion) { + if (cuiVersion < 0) { + throw new IllegalArgumentException("CUI protocol version must be non-negative, but '" + cuiVersion + "' was received."); + } + + this.cuiVersion = cuiVersion; + } + + /** + * Detect date from a user's input. + * + * @param input the input to parse + * @return a date + */ + @Nullable + public Calendar detectDate(String input) { + checkNotNull(input); + + TimeZone tz = TimeZone.getTimeZone(getTimeZone()); + Time.setTimeZone(tz); + Options opt = new com.sk89q.jchronic.Options(); + opt.setNow(Calendar.getInstance(tz)); + Span date = Chronic.parse(input, opt); + if (date == null) { + return null; + } else { + return date.getBeginCalendar(); + } + } + + /** + * Construct a new edit session. + * + * @param actor the actor + * @return an edit session + */ + public EditSession createEditSession(Actor actor) { + checkNotNull(actor); + + World world = null; + if (hasWorldOverride()) { + world = getWorldOverride(); + } else if (actor instanceof Locatable && ((Locatable) actor).getExtent() instanceof World) { + world = (World) ((Locatable) actor).getExtent(); + } + + // Create an edit session + EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder() + .world(world) + .actor(actor) + .maxBlocks(getBlockChangeLimit()) + .tracing(isTracingActions()); + if (actor.isPlayer() && actor instanceof Player) { + builder.blockBag(getBlockBag((Player) actor)); + } + EditSession editSession = builder.build(); + Request.request().setEditSession(editSession); + + editSession.setMask(mask); + prepareEditingExtents(editSession, actor); + + return editSession; + } + + private void prepareEditingExtents(EditSession editSession, Actor actor) { + editSession.setSideEffectApplier(sideEffectSet); + editSession.setReorderMode(reorderMode); + if (editSession.getSurvivalExtent() != null) { + editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); + } + editSession.setTickingWatchdog(tickingWatchdog); + } + + /** + * Gets the side effect applier of this session. + * + * @return the side effect applier + */ + public SideEffectSet getSideEffectSet() { + return this.sideEffectSet; + } + + /** + * Sets the side effect applier for this session. + * + * @param sideEffectSet the side effect applier + */ + public void setSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + /** + * Checks if the session has fast mode enabled. + * + * @return true if fast mode is enabled + */ + @Deprecated + public boolean hasFastMode() { + return !this.sideEffectSet.doesApplyAny(); + } + + /** + * Set fast mode. + * + * @param fastMode true if fast mode is enabled + */ + @Deprecated + public void setFastMode(boolean fastMode) { + this.sideEffectSet = fastMode ? SideEffectSet.none() : SideEffectSet.defaults(); + } + + /** + * Gets the reorder mode of the session. + * + * @return The reorder mode + */ + public EditSession.ReorderMode getReorderMode() { + return reorderMode; + } + + /** + * Sets the reorder mode of the session. + * + * @param reorderMode The reorder mode + */ + public void setReorderMode(EditSession.ReorderMode reorderMode) { + this.reorderMode = reorderMode; + } + + /** + * Get the mask. + * + * @return mask, may be null + */ + public Mask getMask() { + return mask; + } + + /** + * Set a mask. + * + * @param mask mask or null + */ + public void setMask(Mask mask) { + this.mask = mask; + } + + /** + * Get the preferred wand item for this user, or {@code null} to use the default. + * @return item id of wand item, or {@code null} + */ + public String getWandItem() { + return wandItem; + } + + /** + * Get if the selection wand item should use the default, or null if unknown. + * + * @return if it should use the default + */ + public boolean isWandItemDefault() { + if (wandItemDefault == null) { + wandItemDefault = Objects.equals(wandItem, config.wandItem); + setDirty(); + } + return wandItemDefault; + } + + /** + * Get the preferred navigation wand item for this user, or {@code null} to use the default. + * @return item id of nav wand item, or {@code null} + */ + public String getNavWandItem() { + return navWandItem; + } + + /** + * Get if the navigation wand item should use the default, or null if unknown. + * + * @return if it should use the default + */ + public boolean isNavWandItemDefault() { + if (navWandItemDefault == null) { + navWandItemDefault = Objects.equals(navWandItem, config.navigationWand); + setDirty(); + } + return navWandItemDefault; + } + + /** + * Get the last block distribution stored in this session. + * + * @return block distribution or {@code null} + */ + public List> getLastDistribution() { + return lastDistribution == null ? null : Collections.unmodifiableList(lastDistribution); + } + + /** + * Store a block distribution in this session. + */ + public void setLastDistribution(List> dist) { + lastDistribution = dist; + } + + /** + * Call when this session has become inactive. + * + *

This is for internal use only.

+ */ + public void onIdle() { + this.cuiVersion = CUI_VERSION_UNINITIALIZED; + this.hasCUISupport = false; + this.failedCuiAttempts = 0; + } +} diff --git a/src/main/java/com/sk89q/worldedit/MaxBrushRadiusException.java b/src/main/java/com/sk89q/worldedit/MaxBrushRadiusException.java new file mode 100644 index 0000000..76a640c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/MaxBrushRadiusException.java @@ -0,0 +1,27 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +/** + * Thrown when a maximum radius for a brush is reached. + */ +public class MaxBrushRadiusException extends MaxRadiusException { + +} diff --git a/src/main/java/com/sk89q/worldedit/MaxChangedBlocksException.java b/src/main/java/com/sk89q/worldedit/MaxChangedBlocksException.java new file mode 100644 index 0000000..8102478 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/MaxChangedBlocksException.java @@ -0,0 +1,48 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +/** + * Thrown when too many blocks are changed (which may be limited + * due to the configuration). + */ +public class MaxChangedBlocksException extends WorldEditException { + + int maxBlocks; + + /** + * Create a new instance. + * + * @param maxBlocks the maximum number of blocks that can be changed + */ + public MaxChangedBlocksException(int maxBlocks) { + this.maxBlocks = maxBlocks; + } + + /** + * Get the limit. + * + * @return the maximum number of blocks that can be changed + */ + public int getBlockLimit() { + return maxBlocks; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/MaxRadiusException.java b/src/main/java/com/sk89q/worldedit/MaxRadiusException.java new file mode 100644 index 0000000..6641c06 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/MaxRadiusException.java @@ -0,0 +1,28 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +/** + * Thrown when a maximum radius is reached, such as, for example, + * in the case of a sphere command. + */ +public class MaxRadiusException extends WorldEditException { + +} diff --git a/src/main/java/com/sk89q/worldedit/MissingWorldException.java b/src/main/java/com/sk89q/worldedit/MissingWorldException.java new file mode 100644 index 0000000..9ad9385 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/MissingWorldException.java @@ -0,0 +1,32 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import net.kyori.text.TranslatableComponent; + +/** + * Raised when a world is missing but is required. + */ +public class MissingWorldException extends WorldEditException { + + public MissingWorldException() { + super(TranslatableComponent.of("worldedit.error.missing-world")); + } +} diff --git a/src/main/java/com/sk89q/worldedit/NotABlockException.java b/src/main/java/com/sk89q/worldedit/NotABlockException.java new file mode 100644 index 0000000..93d833f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/NotABlockException.java @@ -0,0 +1,66 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.item.ItemType; + +/** + * Raised when an item is used when a block was expected. + */ +public class NotABlockException extends WorldEditException { + + /** + * Create a new instance. + */ + public NotABlockException() { + super(TranslatableComponent.of("worldedit.error.not-a-block")); + } + + /** + * Create a new instance. + * + * @param input the input that was used + */ + @Deprecated + public NotABlockException(String input) { + super(TranslatableComponent.of("worldedit.error.not-a-block.item", TextComponent.of(input))); + } + + /** + * Create a new instance. + * + * @param input the input that was used + */ + @Deprecated + public NotABlockException(int input) { + super(TranslatableComponent.of("worldedit.error.not-a-block.item", TextComponent.of(input))); + } + + /** + * Create a new instance. + * + * @param input the input that was used + */ + public NotABlockException(ItemType input) { + super(TranslatableComponent.of("worldedit.error.not-a-block.item", input.getRichName())); + } +} diff --git a/src/main/java/com/sk89q/worldedit/TracedEditSession.java b/src/main/java/com/sk89q/worldedit/TracedEditSession.java new file mode 100644 index 0000000..e79d54f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/TracedEditSession.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.util.eventbus.EventBus; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; + +/** + * Internal use only. + */ +class TracedEditSession extends EditSession { + + TracedEditSession(EventBus eventBus, @Nullable World world, int maxBlocks, @Nullable BlockBag blockBag, + @Nullable Actor actor, + boolean tracing) { + super(eventBus, world, maxBlocks, blockBag, actor, tracing); + } + + private final Throwable stacktrace = new Throwable("Creation trace."); + + @Override + protected void finalize() throws Throwable { + super.finalize(); + + if (commitRequired()) { + WorldEdit.logger.warn("####### LEFTOVER BUFFER BLOCKS DETECTED #######"); + WorldEdit.logger.warn("This means that some code did not flush their EditSession."); + WorldEdit.logger.warn("Here is a stacktrace from the creation of this EditSession:", stacktrace); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/UnknownDirectionException.java b/src/main/java/com/sk89q/worldedit/UnknownDirectionException.java new file mode 100644 index 0000000..fa6c21c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/UnknownDirectionException.java @@ -0,0 +1,51 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; + +/** + * Thrown when an unknown direction is specified or detected. + */ +public class UnknownDirectionException extends WorldEditException { + + private final String dir; + + /** + * Create a new instance. + * + * @param dir the input that was tried + */ + public UnknownDirectionException(String dir) { + super(TranslatableComponent.of("worldedit.error.unknown-direction", TextComponent.of(dir))); + this.dir = dir; + } + + /** + * Get the direction string that was input. + * + * @return input + */ + public String getDirection() { + return dir; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/UnknownItemException.java b/src/main/java/com/sk89q/worldedit/UnknownItemException.java new file mode 100644 index 0000000..7314079 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/UnknownItemException.java @@ -0,0 +1,48 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +/** + * Thrown when no item exist by the ID. + */ +@Deprecated +public class UnknownItemException extends WorldEditException { + + private final String type; + + /** + * Create a new instance. + * + * @param type the input that was provided + */ + public UnknownItemException(String type) { + this.type = type; + } + + /** + * Get the input. + * + * @return the input + */ + public String getID() { + return type; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/WorldEdit.java b/src/main/java/com/sk89q/worldedit/WorldEdit.java new file mode 100644 index 0000000..7dd5347 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -0,0 +1,848 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import com.google.common.base.Throwables; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.collect.SetMultimap; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.event.platform.BlockInteractEvent; +import com.sk89q.worldedit.event.platform.InputType; +import com.sk89q.worldedit.event.platform.PlayerInputEvent; +import com.sk89q.worldedit.extension.factory.BlockFactory; +import com.sk89q.worldedit.extension.factory.ItemFactory; +import com.sk89q.worldedit.extension.factory.MaskFactory; +import com.sk89q.worldedit.extension.factory.PatternFactory; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.PlatformManager; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.SchematicsEventListener; +import com.sk89q.worldedit.internal.expression.invoke.ReturnException; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.scripting.CraftScriptContext; +import com.sk89q.worldedit.scripting.CraftScriptEngine; +import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine; +import com.sk89q.worldedit.session.SessionManager; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.asset.AssetLoaders; +import com.sk89q.worldedit.util.concurrency.EvenMoreExecutors; +import com.sk89q.worldedit.util.eventbus.EventBus; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException; +import com.sk89q.worldedit.util.io.file.FilenameException; +import com.sk89q.worldedit.util.io.file.FilenameResolutionException; +import com.sk89q.worldedit.util.io.file.InvalidFilenameException; +import com.sk89q.worldedit.util.task.SimpleSupervisor; +import com.sk89q.worldedit.util.task.Supervisor; +import com.sk89q.worldedit.util.translation.TranslationManager; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BundledBlockData; +import com.sk89q.worldedit.world.registry.BundledItemData; +import com.sk89q.worldedit.world.registry.LegacyMapper; +import org.apache.logging.log4j.Logger; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import javax.annotation.Nullable; +import javax.script.ScriptException; + +import static com.sk89q.worldedit.event.platform.Interaction.HIT; +import static com.sk89q.worldedit.event.platform.Interaction.OPEN; + +/** + * The entry point and container for a working implementation of WorldEdit. + * + *

An instance handles event handling; block, mask, pattern, etc. registration; + * the management of sessions; the creation of {@link EditSession}s; and more. + * In order to use WorldEdit, at least one {@link Platform} must be registered + * with WorldEdit using {@link PlatformManager#register(Platform)} on the + * manager retrieved using {@link WorldEdit#getPlatformManager()}.

+ * + *

An instance of WorldEdit can be retrieved using the static + * method {@link WorldEdit#getInstance()}, which is shared among all + * platforms within the same classloader hierarchy.

+ */ +public final class WorldEdit { + + /** + * This is for internal use only. + */ + public static final Logger logger = LogManagerCompat.getLogger(); + + private static final WorldEdit instance = new WorldEdit(); + private static String version; + + private final EventBus eventBus = new EventBus(); + private final PlatformManager platformManager = new PlatformManager(this); + @Deprecated + private final EditSessionFactory editSessionFactory = new EditSessionFactory.EditSessionFactoryImpl(); + private final SessionManager sessions = new SessionManager(this); + private final ListeningExecutorService executorService = MoreExecutors.listeningDecorator( + EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20, "WorldEdit Task Executor - %s")); + private final Supervisor supervisor = new SimpleSupervisor(); + private final AssetLoaders assetLoaders = new AssetLoaders(this); + + private final BlockFactory blockFactory = new BlockFactory(this); + private final ItemFactory itemFactory = new ItemFactory(this); + private final MaskFactory maskFactory = new MaskFactory(this); + private final PatternFactory patternFactory = new PatternFactory(this); + + static { + getVersion(); + } + + private WorldEdit() { + eventBus.register(new SchematicsEventListener()); + } + + /** + * Gets the current instance of this class. + * + *

An instance will always be available, but no platform may yet be + * registered with WorldEdit, meaning that a number of operations + * may fail. However, event handlers can be registered.

+ * + * @return an instance of WorldEdit. + */ + public static WorldEdit getInstance() { + return instance; + } + + /** + * Get the platform manager, where platforms (that implement WorldEdit) + * can be registered and information about registered platforms can + * be queried. + * + * @return the platform manager + */ + public PlatformManager getPlatformManager() { + return platformManager; + } + + /** + * Get the event bus for WorldEdit. + * + *

Event handlers can be registered on the event bus.

+ * + * @return the event bus + */ + public EventBus getEventBus() { + return eventBus; + } + + /** + * Get the supervisor. Internal, not for API use. + * + * @return the supervisor + */ + public Supervisor getSupervisor() { + return supervisor; + } + + /** + * Get the executor service. Internal, not for API use. + * + * @return the executor service + */ + public ListeningExecutorService getExecutorService() { + return executorService; + } + + /** + * Get the block factory from which new {@link BlockStateHolder}s can be + * constructed. + * + * @return the block factory + */ + public BlockFactory getBlockFactory() { + return blockFactory; + } + + /** + * Get the item factory from which new {@link BaseItem}s can be + * constructed. + * + * @return the item factory + */ + public ItemFactory getItemFactory() { + return itemFactory; + } + + /** + * Get the mask factory from which new {@link Mask}s + * can be constructed. + * + * @return the mask factory + */ + public MaskFactory getMaskFactory() { + return maskFactory; + } + + /** + * Get the pattern factory from which new {@link Pattern}s + * can be constructed. + * + * @return the pattern factory + */ + public PatternFactory getPatternFactory() { + return patternFactory; + } + + /** + * Return the session manager. + * + * @return the session manager + */ + public SessionManager getSessionManager() { + return sessions; + } + + /** + * Return the translation manager. + * + * @return the translation manager + */ + public TranslationManager getTranslationManager() { + return getPlatformManager().queryCapability(Capability.CONFIGURATION) + .getTranslationManager(); + } + + /** + * Return the asset loaders instance. + * + * @return the asset loaders instance + */ + public AssetLoaders getAssetLoaders() { + return assetLoaders; + } + + /** + * Gets the path to a file. This method will check to see if the filename + * has valid characters and has an extension. It also prevents directory + * traversal exploits by checking the root directory and the file directory. + * On success, a {@code java.io.File} object will be returned. + * + * @param actor the actor + * @param dir sub-directory to look in + * @param filename filename (user-submitted) + * @param defaultExt append an extension if missing one, null to not use + * @param extensions list of extensions, null for any + * @return a file + * @throws FilenameException thrown if the filename is invalid + */ + public File getSafeSaveFile(Actor actor, File dir, String filename, String defaultExt, String... extensions) throws FilenameException { + return getSafeFile(actor, dir, filename, defaultExt, extensions, true); + } + + /** + * Gets the path to a file. This method will check to see if the filename + * has valid characters and has an extension. It also prevents directory + * traversal exploits by checking the root directory and the file directory. + * On success, a {@code java.io.File} object will be returned. + * + * @param actor the actor + * @param dir sub-directory to look in + * @param filename filename (user-submitted) + * @param defaultExt append an extension if missing one, null to not use + * @param extensions list of extensions, null for any + * @return a file + * @throws FilenameException thrown if the filename is invalid + */ + public File getSafeOpenFile(Actor actor, File dir, String filename, String defaultExt, String... extensions) throws FilenameException { + return getSafeFile(actor, dir, filename, defaultExt, extensions, false); + } + + /** + * Get a safe path to a file. + * + * @param actor the actor + * @param dir sub-directory to look in + * @param filename filename (user-submitted) + * @param defaultExt append an extension if missing one, null to not use + * @param extensions list of extensions, null for any + * @param isSave true if the purpose is for saving + * @return a file + * @throws FilenameException thrown if the filename is invalid + */ + private File getSafeFile(@Nullable Actor actor, File dir, String filename, String defaultExt, String[] extensions, boolean isSave) throws FilenameException { + if (extensions != null && (extensions.length == 1 && extensions[0] == null)) { + extensions = null; + } + + File f; + + if (filename.equals("#") && actor != null) { + if (isSave) { + f = actor.openFileSaveDialog(extensions); + } else { + f = actor.openFileOpenDialog(extensions); + } + + if (f == null) { + throw new FileSelectionAbortedException(TranslatableComponent.of("worldedit.error.no-file-selected")); + } + } else { + List exts = extensions == null ? ImmutableList.of(defaultExt) : Lists.asList(defaultExt, extensions); + f = getSafeFileWithExtensions(dir, filename, exts, isSave); + } + + try { + Path filePath = Paths.get(f.toURI()).normalize(); + Path dirPath = Paths.get(dir.toURI()).normalize(); + + boolean inDir = filePath.startsWith(dirPath); + Path existingParent = filePath; + do { + existingParent = existingParent.getParent(); + } while (existingParent != null && !existingParent.toFile().exists()); + + boolean isSym = existingParent != null && !existingParent.toRealPath().equals(existingParent); + if (!inDir || (!getConfiguration().allowSymlinks && isSym)) { + throw new FilenameResolutionException(filename, TranslatableComponent.of("worldedit.error.file-resolution.outside-root")); + } + + return filePath.toFile(); + } catch (IOException | InvalidPathException e) { + throw new FilenameResolutionException(filename, TranslatableComponent.of("worldedit.error.file-resolution.resolve-failed")); + } + } + + private File getSafeFileWithExtensions(File dir, String filename, List exts, boolean isSave) throws InvalidFilenameException { + if (isSave) { + // First is default, only use that. + if (exts.size() != 1) { + exts = exts.subList(0, 1); + } + } else { + int dot = filename.lastIndexOf('.'); + if (dot < 0 || dot == filename.length() - 1) { + String currentExt = filename.substring(dot + 1); + if (exts.contains(currentExt) && checkFilename(filename)) { + File f = new File(dir, filename); + if (f.exists()) { + return f; + } + } + } + } + File result = null; + for (Iterator iter = exts.iterator(); iter.hasNext() && (result == null || (!isSave && !result.exists()));) { + result = getSafeFileWithExtension(dir, filename, iter.next()); + } + if (result == null) { + throw new InvalidFilenameException(filename, TranslatableComponent.of("worldedit.error.invalid-filename.invalid-characters")); + } + return result; + } + + private File getSafeFileWithExtension(File dir, String filename, String extension) { + if (extension != null) { + int dot = filename.lastIndexOf('.'); + if (dot < 0 || dot == filename.length() - 1 || !filename.substring(dot + 1).equalsIgnoreCase(extension)) { + filename += "." + extension; + } + } + + if (!checkFilename(filename)) { + return null; + } + + return new File(dir, filename); + } + + private boolean checkFilename(String filename) { + return filename.matches("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+\\.[A-Za-z0-9]+$"); + } + + /** + * Load the bundled mappings. + */ + public void loadMappings() { + BundledBlockData.getInstance(); // Load block registry + BundledItemData.getInstance(); // Load item registry + LegacyMapper.getInstance(); // Load item registry + } + + /** + * Checks to see if the specified radius is within bounds. + * + * @param radius the radius + * @throws MaxRadiusException if the radius is bigger than the configured radius + */ + public void checkMaxRadius(double radius) throws MaxRadiusException { + if (getConfiguration().maxRadius > 0 && radius > getConfiguration().maxRadius) { + throw new MaxRadiusException(); + } + } + + /** + * Checks to see if the specified brush radius is within bounds. + * + * @param radius the radius + * @throws MaxBrushRadiusException if the radius is bigger than the configured radius + */ + public void checkMaxBrushRadius(double radius) throws MaxBrushRadiusException { + if (getConfiguration().maxBrushRadius > 0 && radius > getConfiguration().maxBrushRadius) { + throw new MaxBrushRadiusException(); + } + } + + /** + * Get a file relative to the defined working directory. If the specified + * path is absolute, then the working directory is not used. + * + * @param path the subpath under the working directory + * @return a working directory + * @deprecated Use {@link WorldEdit#getWorkingDirectoryPath(String)} instead + */ + @Deprecated + public File getWorkingDirectoryFile(String path) { + return getWorkingDirectoryPath(path).toFile(); + } + + /** + * Get a file relative to the defined working directory. If the specified + * path is absolute, then the working directory is not used. + * + * @param path the subpath under the working directory + * @return a working directory + */ + public Path getWorkingDirectoryPath(String path) { + Path p = Paths.get(path); + if (p.isAbsolute()) { + return p; + } + + return getConfiguration().getWorkingDirectoryPath().resolve(path); + } + + /** + * Get the direction vector for a player's direction. + * + * @param player the player + * @param dirStr the direction string + * @return a direction vector + * @throws UnknownDirectionException thrown if the direction is not known, or a relative direction is used with null player + */ + public BlockVector3 getDirection(@Nullable Player player, String dirStr) throws UnknownDirectionException { + dirStr = dirStr.toLowerCase(Locale.ROOT); + + final Direction dir = getPlayerDirection(player, dirStr); + + if (dir.isUpright() || dir.isCardinal()) { + return dir.toBlockVector(); + } else { + throw new UnknownDirectionException(dir.name()); + } + } + + /** + * Get the direction vector for a player's direction. + * + * @param player the player + * @param dirStr the direction string + * @return a direction vector + * @throws UnknownDirectionException thrown if the direction is not known, or a relative direction is used with null player + */ + public BlockVector3 getDiagonalDirection(@Nullable Player player, String dirStr) throws UnknownDirectionException { + dirStr = dirStr.toLowerCase(Locale.ROOT); + + final Direction dir = getPlayerDirection(player, dirStr); + + if (dir.isCardinal() || dir.isOrdinal() || dir.isUpright()) { + return dir.toBlockVector(); + } + + throw new UnknownDirectionException(dir.name()); + } + + private static final Map NAME_TO_DIRECTION_MAP; + + static { + SetMultimap directionNames = HashMultimap.create(); + for (Direction direction : Direction.valuesOf( + Direction.Flag.CARDINAL | Direction.Flag.UPRIGHT + )) { + String name = direction.name().toLowerCase(Locale.ROOT); + for (int i = 1; i <= name.length(); i++) { + directionNames.put(direction, name.substring(0, i)); + } + } + ImmutableMap.Builder nameToDirectionMap = ImmutableMap.builder(); + for (Direction direction : directionNames.keySet()) { + directionNames.get(direction).forEach(name -> + nameToDirectionMap.put(name, direction) + ); + } + for (Direction direction : ImmutableList.of(Direction.NORTH, Direction.SOUTH)) { + for (Direction diagonal : ImmutableList.of(Direction.WEST, Direction.EAST)) { + for (String dirName : directionNames.get(direction)) { + for (String diagName : directionNames.get(diagonal)) { + nameToDirectionMap.put(dirName + diagName, Direction.valueOf( + direction.name() + diagonal.name() + )); + } + } + } + } + NAME_TO_DIRECTION_MAP = nameToDirectionMap.build(); + } + + /** + * Get the direction vector for a player's direction. + * + * @param player the player + * @param dirStr the direction string + * @return a direction enum value + * @throws UnknownDirectionException thrown if the direction is not known, or a relative direction is used with null player + */ + private Direction getPlayerDirection(@Nullable Player player, String dirStr) throws UnknownDirectionException { + Direction byName = NAME_TO_DIRECTION_MAP.get(dirStr); + if (byName != null) { + return byName; + } + switch (dirStr) { + case "m": + case "me": + case "f": + case "forward": + return getDirectionRelative(player, 0); + + case "b": + case "back": + Direction dir = getDirectionRelative(player, 180); + if (dir.isUpright()) { + // If this is an upright direction, flip it. + dir = dir == Direction.UP ? Direction.DOWN : Direction.UP; + } + return dir; + + case "l": + case "left": + return getDirectionRelative(player, -90); + + case "r": + case "right": + return getDirectionRelative(player, 90); + + default: + throw new UnknownDirectionException(dirStr); + } + } + + private Direction getDirectionRelative(Player player, int yawOffset) throws UnknownDirectionException { + if (player != null) { + return player.getCardinalDirection(yawOffset); + } + throw new UnknownDirectionException("Only a player can use relative directions"); + } + + /** + * Flush a block bag's changes to a player. + * + * @param actor the actor + * @param editSession the edit session + */ + public void flushBlockBag(Actor actor, EditSession editSession) { + BlockBag blockBag = editSession.getBlockBag(); + + if (blockBag != null) { + blockBag.flushChanges(); + } + + Map missingBlocks = editSession.popMissingBlocks(); + + if (!missingBlocks.isEmpty()) { + TextComponent.Builder str = TextComponent.builder(); + str.append("Missing these blocks: "); + int size = missingBlocks.size(); + int i = 0; + + for (Map.Entry blockTypeIntegerEntry : missingBlocks.entrySet()) { + str.append((blockTypeIntegerEntry.getKey()).getRichName()); + + str.append(" [Amt: ") + .append(String.valueOf(blockTypeIntegerEntry.getValue())) + .append("]"); + + ++i; + + if (i != size) { + str.append(", "); + } + } + + actor.printError(str.build()); + } + } + + /** + * Called on arm swing. + * + * @param player the player + * @return true if the swing was handled + */ + public boolean handleArmSwing(Player player) { + PlayerInputEvent event = new PlayerInputEvent(player, InputType.PRIMARY); + getEventBus().post(event); + return event.isCancelled(); + } + + /** + * Called on right click (not on a block). + * + * @param player the player + * @return true if the right click was handled + */ + public boolean handleRightClick(Player player) { + PlayerInputEvent event = new PlayerInputEvent(player, InputType.SECONDARY); + getEventBus().post(event); + return event.isCancelled(); + } + + /** + * Called on right click. + * + * @param player the player + * @param clicked the clicked block + * @return false if you want the action to go through + */ + @Deprecated + public boolean handleBlockRightClick(Player player, Location clicked) { + return handleBlockRightClick(player, clicked, null); + } + + /** + * Called on right click. + * + * @param player the player + * @param clicked the clicked block + * @param face The clicked face + * @return false if you want the action to go through + */ + public boolean handleBlockRightClick(Player player, Location clicked, @Nullable Direction face) { + BlockInteractEvent event = new BlockInteractEvent(player, clicked, face, OPEN); + getEventBus().post(event); + return event.isCancelled(); + } + + /** + * Called on left click. + * + * @param player the player + * @param clicked the clicked block + * @return false if you want the action to go through + */ + @Deprecated + public boolean handleBlockLeftClick(Player player, Location clicked) { + return handleBlockLeftClick(player, clicked, null); + } + + /** + * Called on left click. + * + * @param player the player + * @param clicked the clicked block + * @param face The clicked face + * @return false if you want the action to go through + */ + public boolean handleBlockLeftClick(Player player, Location clicked, @Nullable Direction face) { + BlockInteractEvent event = new BlockInteractEvent(player, clicked, face, HIT); + getEventBus().post(event); + return event.isCancelled(); + } + + /** + * Executes a WorldEdit script. + * + * @param player the player + * @param f the script file to execute + * @param args arguments for the script + * @throws WorldEditException if something goes wrong + */ + public void runScript(Player player, File f, String[] args) throws WorldEditException { + String filename = f.getPath(); + int index = filename.lastIndexOf('.'); + String ext = filename.substring(index + 1); + + if (!ext.equalsIgnoreCase("js")) { + player.printError(TranslatableComponent.of("worldedit.script.unsupported")); + return; + } + + String script; + + try { + InputStream file; + + if (!f.exists()) { + file = WorldEdit.class.getResourceAsStream("craftscripts/" + filename); + + if (file == null) { + player.printError(TranslatableComponent.of("worldedit.script.file-not-found", TextComponent.of(filename))); + return; + } + } else { + file = new FileInputStream(f); + } + + DataInputStream in = new DataInputStream(file); + byte[] data = new byte[in.available()]; + in.readFully(data); + in.close(); + script = new String(data, 0, data.length, StandardCharsets.UTF_8); + } catch (IOException e) { + player.printError(TranslatableComponent.of("worldedit.script.read-error", TextComponent.of(e.getMessage()))); + return; + } + + LocalSession session = getSessionManager().get(player); + CraftScriptContext scriptContext = new CraftScriptContext(this, getPlatformManager().queryCapability(Capability.USER_COMMANDS), + getConfiguration(), session, player, args); + + CraftScriptEngine engine; + + try { + engine = new RhinoCraftScriptEngine(); + } catch (NoClassDefFoundError ignored) { + player.printError(TranslatableComponent.of("worldedit.script.no-script-engine")); + return; + } + + engine.setTimeLimit(getConfiguration().scriptTimeout); + + Map vars = new HashMap<>(); + vars.put("argv", args); + vars.put("context", scriptContext); + vars.put("player", player); + + try { + engine.evaluate(script, filename, vars); + } catch (ScriptException e) { + // non-exceptional return check + if (!(Throwables.getRootCause(e) instanceof ReturnException)) { + player.printError(TranslatableComponent.of("worldedit.script.failed", TextComponent.of(e.getMessage(), TextColor.WHITE))); + logger.warn("Failed to execute script", e); + } + } catch (NumberFormatException | WorldEditException e) { + throw e; + } catch (Throwable e) { + player.printError(TranslatableComponent.of("worldedit.script.failed-console", TextComponent.of(e.getClass().getCanonicalName(), + TextColor.WHITE))); + logger.warn("Failed to execute script", e); + } finally { + for (EditSession editSession : scriptContext.getEditSessions()) { + editSession.close(); + session.remember(editSession); + } + } + } + + /** + * Get Worldedit's configuration. + * + * @return a configuration + */ + public LocalConfiguration getConfiguration() { + return getPlatformManager().getConfiguration(); + } + + /** + * Get a factory for {@link EditSession}s. + * + * @deprecated Use {@link #newEditSessionBuilder()} instead. See {@link EditSessionFactory} for details. + */ + @Deprecated + public EditSessionFactory getEditSessionFactory() { + return editSessionFactory; + } + + /** + * Create a builder for {@link EditSession}s. + */ + public EditSessionBuilder newEditSessionBuilder() { + return new EditSessionBuilder(eventBus); + } + + /** + * Shorthand for {@code newEditSessionBuilder().world(world).build()}. + * + * @param world the world + * @return the new {@link EditSession} + */ + public EditSession newEditSession(@Nullable World world) { + return newEditSessionBuilder().world(world).build(); + } + + /** + * Shorthand for {@code newEditSessionBuilder().locatableActor(locatableActor).build()}. + * + * @param locatableActor the actor + * @return the new {@link EditSession} + */ + public
EditSession newEditSession(A locatableActor) { + return newEditSessionBuilder().locatableActor(locatableActor).build(); + } + + /** + * Get the version. + * + * @return the version of WorldEdit + */ + public static String getVersion() { + if (version != null) { + return version; + } + + WorldEditManifest manifest = WorldEditManifest.load(); + + return version = manifest.getWorldEditVersion(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/WorldEditException.java b/src/main/java/com/sk89q/worldedit/WorldEditException.java new file mode 100644 index 0000000..5ba203c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/WorldEditException.java @@ -0,0 +1,111 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import com.sk89q.worldedit.util.formatting.WorldEditText; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; + +import java.util.Locale; + +/** + * Parent for all WorldEdit exceptions. + */ +public abstract class WorldEditException extends Exception { + + private final Component message; + + /** + * Create a new exception. + */ + protected WorldEditException() { + this.message = null; + } + + /** + * Create a new exception with a message. + * + * @param message the message + * @deprecated Use component version + */ + @Deprecated + protected WorldEditException(String message) { + super(message); + + this.message = TextComponent.of(message); + } + + /** + * Create a new exception with a message. + * + * @param message the message + */ + protected WorldEditException(Component message) { + super(WorldEditText.reduceToText(message, Locale.getDefault())); + + this.message = message; + } + + /** + * Create a new exception with a message and a cause. + * + * @param message the message + * @param cause the cause + * @deprecated Use component version + */ + @Deprecated + protected WorldEditException(String message, Throwable cause) { + super(message, cause); + + this.message = TextComponent.of(message); + } + + /** + * Create a new exception with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + protected WorldEditException(Component message, Throwable cause) { + super(WorldEditText.reduceToText(message, Locale.getDefault()), cause); + + this.message = message; + } + + /** + * Create a new exception with a cause. + * + * @param cause the cause + */ + protected WorldEditException(Throwable cause) { + super(cause); + + this.message = null; + } + + /** + * Get the message of this exception as a rich text component. + * + * @return The rich message + */ + public Component getRichMessage() { + return this.message; + } +} diff --git a/src/main/java/com/sk89q/worldedit/WorldEditManifest.java b/src/main/java/com/sk89q/worldedit/WorldEditManifest.java new file mode 100644 index 0000000..8d8de2a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/WorldEditManifest.java @@ -0,0 +1,108 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.JarURLConnection; +import java.net.URL; +import java.util.function.Supplier; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import javax.annotation.Nullable; + +/** + * Represents WorldEdit info from the MANIFEST.MF file. + */ +public class WorldEditManifest { + + public static final String WORLD_EDIT_VERSION = "WorldEdit-Version"; + public static final String WORLD_EDIT_KIND = "WorldEdit-Kind"; + + public enum Kind { + MOD("mods"), + PLUGIN("plugins"), + UNKNOWN("mods/plugins"), + ; + + public final String folderName; + + Kind(String folderName) { + this.folderName = folderName; + } + } + + public static WorldEditManifest load() { + Attributes attributes = readAttributes(); + Kind kind; + try { + kind = Kind.valueOf(readAttribute(attributes, WORLD_EDIT_KIND, () -> "UNKNOWN")); + } catch (IllegalArgumentException e) { + kind = Kind.UNKNOWN; + } + return new WorldEditManifest( + readAttribute(attributes, WORLD_EDIT_VERSION, () -> "(unknown)"), + kind + ); + } + + private static @Nullable Attributes readAttributes() { + Class clazz = WorldEditManifest.class; + String className = clazz.getSimpleName() + ".class"; + String classPath = clazz.getResource(className).toString(); + if (!classPath.startsWith("jar")) { + return null; + } + + try { + URL url = new URL(classPath); + JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); + Manifest manifest = jarConnection.getManifest(); + return manifest.getMainAttributes(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private static String readAttribute(@Nullable Attributes attributes, String name, + Supplier defaultAction) { + if (attributes == null) { + return defaultAction.get(); + } + String value = attributes.getValue(name); + return value != null ? value : defaultAction.get(); + } + + private final String worldEditVersion; + private final Kind worldEditKind; + + private WorldEditManifest(String worldEditVersion, Kind worldEditKind) { + this.worldEditVersion = worldEditVersion; + this.worldEditKind = worldEditKind; + } + + public String getWorldEditVersion() { + return worldEditVersion; + } + + public Kind getWorldEditKind() { + return worldEditKind; + } +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java b/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java new file mode 100644 index 0000000..a365bc4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java @@ -0,0 +1,97 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.blocks; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.NbtValued; +import com.sk89q.worldedit.world.item.ItemType; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents an item, without an amount value. See {@link BaseItemStack} + * for an instance with stack amount information. + * + *

This class may be removed in the future.

+ */ +public class BaseItem implements NbtValued { + + private ItemType itemType; + @Nullable + private CompoundTag nbtData; + + /** + * Construct the object. + * + * @param itemType Type of the item + */ + public BaseItem(ItemType itemType) { + checkNotNull(itemType); + this.itemType = itemType; + } + + /** + * Construct the object. + * + * @param itemType Type of the item + * @param tag NBT Compound tag + */ + public BaseItem(ItemType itemType, @Nullable CompoundTag tag) { + checkNotNull(itemType); + this.itemType = itemType; + this.nbtData = tag; + } + + /** + * Get the type of item. + * + * @return the type + */ + public ItemType getType() { + return this.itemType; + } + + /** + * Set the type of the item. + * + * @param itemType The type to set + */ + public void setType(ItemType itemType) { + this.itemType = itemType; + } + + @Override + public boolean hasNbtData() { + return this.nbtData != null; + } + + @Nullable + @Override + public CompoundTag getNbtData() { + return this.nbtData; + } + + @Override + public void setNbtData(@Nullable CompoundTag nbtData) { + this.nbtData = nbtData; + } +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java b/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java new file mode 100644 index 0000000..5350965 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java @@ -0,0 +1,91 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.blocks; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import net.kyori.text.Component; +import com.sk89q.worldedit.world.item.ItemType; + +/** + * Represents a stack of BaseItems. + * + *

This class may be removed in the future.

+ */ +public class BaseItemStack extends BaseItem { + + private int amount = 1; + + /** + * Construct the object with default stack size of one, with damage value of 0. + * + * @param itemType The item type + */ + public BaseItemStack(ItemType itemType) { + super(itemType); + } + + /** + * Construct the object. + * + * @param itemType The item type + * @param amount amount in the stack + */ + public BaseItemStack(ItemType itemType, int amount) { + super(itemType); + this.amount = amount; + } + + /** + * Construct the object. + * + * @param id The item type + * @param tag Tag value + * @param amount amount in the stack + */ + public BaseItemStack(ItemType id, CompoundTag tag, int amount) { + super(id, tag); + this.amount = amount; + } + + /** + * Get the number of items in the stack. + * + * @return the amount + */ + public int getAmount() { + return amount; + } + + /** + * Set the amount of items in the stack. + * + * @param amount the amount to set + */ + public void setAmount(int amount) { + this.amount = amount; + } + + public Component getRichName() { + return WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS) + .getRegistries().getItemRegistry().getRichName(this); + } +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/Blocks.java b/src/main/java/com/sk89q/worldedit/blocks/Blocks.java new file mode 100644 index 0000000..87b8b52 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/blocks/Blocks.java @@ -0,0 +1,83 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.blocks; + +import com.google.common.collect.Maps; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.Collection; +import java.util.Map; + +/** + * Block-related utility methods. + */ +public final class Blocks { + + private Blocks() { + } + + /** + * Checks whether a given block is in a list of base blocks. + * + * @param collection the collection + * @param o the block + * @return true if the collection contains the given block + */ + public static > boolean containsFuzzy(Collection> collection, B o) { + // Allow masked data in the searchBlocks to match various types + for (BlockStateHolder b : collection) { + if (b.equalsFuzzy(o)) { + return true; + } + } + return false; + } + + /** + * Parses a string->string map to find the matching Property and values for the given BlockType. + * + * @param states the desired states and values + * @param type the block type to get properties and values for + * @return a property->value map + */ + public static Map, Object> resolveProperties(Map states, BlockType type) { + Map> existing = type.getPropertyMap(); + Map, Object> newMap = Maps.newHashMap(); + states.forEach((key, value) -> { + @SuppressWarnings("unchecked") + Property prop = (Property) existing.get(key); + if (prop == null) { + return; + } + Object val = null; + try { + val = prop.getValueFor(value); + } catch (IllegalArgumentException ignored) { + } + if (val == null) { + return; + } + newMap.put(prop, val); + }); + return newMap; + } +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java new file mode 100644 index 0000000..e7e4830 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java @@ -0,0 +1,231 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.blocks; + +import com.google.common.collect.ImmutableMap; +import com.sk89q.jnbt.*; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.storage.InvalidFormatException; + +import java.util.HashMap; +import java.util.Map; + +/** + * A mob spawner block. + */ +public class MobSpawnerBlock extends BaseBlock { + + private String mobType; + private short delay = -1; + + // advanced mob spawner features + private short spawnCount = 4; + private short spawnRange = 4; + private CompoundTag spawnData; + private ListTag spawnPotentials; + private short minSpawnDelay = 200; + private short maxSpawnDelay = 800; + private short maxNearbyEntities = 6; + private short requiredPlayerRange = 16; + + /** + * Construct the mob spawner block with a specified data value. + * + * @param blockState The block state + */ + public MobSpawnerBlock(BlockState blockState) { + super(blockState); + } + + /** + * Construct the mob spawner block. + * + * @param blockState The block state + * @param mobType mob type + */ + public MobSpawnerBlock(BlockState blockState, String mobType) { + super(blockState); + this.mobType = mobType; + } + + /** + * Get the mob type. + * + * @return the mob type + */ + public String getMobType() { + return mobType; + } + + /** + * Set the mob type. + * + * @param mobType the mob type + */ + public void setMobType(String mobType) { + this.mobType = mobType; + } + + /** + * Get the spawn delay. + * + * @return the delay + */ + public short getDelay() { + return delay; + } + + /** + * Set the spawn delay. + * + * @param delay the delay to set + */ + public void setDelay(short delay) { + this.delay = delay; + } + + @Override + public boolean hasNbtData() { + return true; + } + + @Override + public String getNbtId() { + return "minecraft:mob_spawner"; + } + + @Override + public CompoundTag getNbtData() { + Map values = new HashMap<>(); + values.put("Delay", new ShortTag(delay)); + values.put("SpawnCount", new ShortTag(spawnCount)); + values.put("SpawnRange", new ShortTag(spawnRange)); + values.put("MinSpawnDelay", new ShortTag(minSpawnDelay)); + values.put("MaxSpawnDelay", new ShortTag(maxSpawnDelay)); + values.put("MaxNearbyEntities", new ShortTag(maxNearbyEntities)); + values.put("RequiredPlayerRange", new ShortTag(requiredPlayerRange)); + if (spawnData == null) { + values.put("SpawnData", new CompoundTag(ImmutableMap.of("entity", new CompoundTag(ImmutableMap.of("id", new StringTag(mobType)))))); + } else { + values.put("SpawnData", new CompoundTag(spawnData.getValue())); + } + if (spawnPotentials != null) { + values.put("SpawnPotentials", new ListTag(CompoundTag.class, spawnPotentials.getValue())); + } + + return new CompoundTag(values); + } + + @Override + public void setNbtData(CompoundTag rootTag) { + if (rootTag == null) { + return; + } + + Map values = rootTag.getValue(); + + Tag t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) { + throw new RuntimeException(String.format("'%s' tile entity expected", getNbtId())); + } + + CompoundTag spawnDataTag; + String mobType; + ShortTag delayTag; + + try { + spawnDataTag = NBTUtils.getChildTag(values, "SpawnData", CompoundTag.class); + mobType = spawnDataTag.getString("id"); + if (mobType.equals("")) { + throw new InvalidFormatException("No spawn id."); + } + this.mobType = mobType; + this.spawnData = spawnDataTag; + } catch (InvalidFormatException ignored) { + throw new RuntimeException("Invalid mob spawner data: no SpawnData and/or no Delay"); + } + try { + delayTag = NBTUtils.getChildTag(values, "Delay", ShortTag.class); + this.delay = delayTag.getValue(); + } catch (InvalidFormatException ignored) { + this.delay = -1; + } + + ShortTag spawnCountTag = null; + ShortTag spawnRangeTag = null; + ShortTag minSpawnDelayTag = null; + ShortTag maxSpawnDelayTag = null; + ShortTag maxNearbyEntitiesTag = null; + ShortTag requiredPlayerRangeTag = null; + ListTag spawnPotentialsTag = null; + try { + spawnCountTag = NBTUtils.getChildTag(values, "SpawnCount", ShortTag.class); + } catch (InvalidFormatException ignored) { + } + try { + spawnRangeTag = NBTUtils.getChildTag(values, "SpawnRange", ShortTag.class); + } catch (InvalidFormatException ignored) { + } + try { + minSpawnDelayTag = NBTUtils.getChildTag(values, "MinSpawnDelay", ShortTag.class); + } catch (InvalidFormatException ignored) { + } + try { + maxSpawnDelayTag = NBTUtils.getChildTag(values, "MaxSpawnDelay", ShortTag.class); + } catch (InvalidFormatException ignored) { + } + try { + maxNearbyEntitiesTag = NBTUtils.getChildTag(values, "MaxNearbyEntities", ShortTag.class); + } catch (InvalidFormatException ignored) { + } + try { + requiredPlayerRangeTag = NBTUtils.getChildTag(values, "RequiredPlayerRange", ShortTag.class); + } catch (InvalidFormatException ignored) { + } + try { + spawnPotentialsTag = NBTUtils.getChildTag(values, "SpawnPotentials", ListTag.class); + } catch (InvalidFormatException ignored) { + } + + if (spawnCountTag != null) { + this.spawnCount = spawnCountTag.getValue(); + } + if (spawnRangeTag != null) { + this.spawnRange = spawnRangeTag.getValue(); + } + if (minSpawnDelayTag != null) { + this.minSpawnDelay = minSpawnDelayTag.getValue(); + } + if (maxSpawnDelayTag != null) { + this.maxSpawnDelay = maxSpawnDelayTag.getValue(); + } + if (maxNearbyEntitiesTag != null) { + this.maxNearbyEntities = maxNearbyEntitiesTag.getValue(); + } + if (requiredPlayerRangeTag != null) { + this.requiredPlayerRange = requiredPlayerRangeTag.getValue(); + } + if (spawnPotentialsTag != null) { + this.spawnPotentials = new ListTag(CompoundTag.class, spawnPotentialsTag.getValue()); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java b/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java new file mode 100644 index 0000000..d18b03b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java @@ -0,0 +1,169 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.blocks; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.util.gson.GsonUtil; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Represents a sign block. + */ +public class SignBlock extends BaseBlock { + + private String[] text; + + private static final String EMPTY = "{\"text\":\"\"}"; + + /** + * Construct the sign with text. + * + * @param blockState The block state + * @param text lines of text + */ + public SignBlock(BlockState blockState, String[] text) { + super(blockState); + if (text == null) { + this.text = new String[] { EMPTY, EMPTY, EMPTY, EMPTY }; + return; + } + for (int i = 0; i < text.length; i++) { + if (text[i].isEmpty()) { + text[i] = EMPTY; + } else { + text[i] = "{\"text\":" + GsonUtil.stringValue(text[i]) + "}"; + } + } + this.text = text; + } + + private boolean isLegacy() { + int dataVersion = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion(); + return dataVersion < Constants.DATA_VERSION_MC_1_20; + } + + /** + * Get the text. + * + * @return the text + */ + public String[] getText() { + return text; + } + + /** + * Set the text. + * + * @param text the text to set + */ + public void setText(String[] text) { + if (text == null) { + throw new IllegalArgumentException("Can't set null text for a sign"); + } + this.text = text; + } + + @Override + public boolean hasNbtData() { + return true; + } + + @Override + public String getNbtId() { + return "minecraft:sign"; + } + + @Override + public CompoundTag getNbtData() { + Map values = new HashMap<>(); + if (isLegacy()) { + values.put("Text1", new StringTag(text[0])); + values.put("Text2", new StringTag(text[1])); + values.put("Text3", new StringTag(text[2])); + values.put("Text4", new StringTag(text[3])); + } else { + ListTag messages = new ListTag(StringTag.class, Arrays.stream(text).map(StringTag::new).collect(Collectors.toList())); + Map frontTextTag = new HashMap<>(); + frontTextTag.put("messages", messages); + values.put("front_text", new CompoundTag(frontTextTag)); + } + return new CompoundTag(values); + } + + @Override + public void setNbtData(CompoundTag rootTag) { + if (rootTag == null) { + return; + } + + Map values = rootTag.getValue(); + + Tag t; + + text = new String[] { EMPTY, EMPTY, EMPTY, EMPTY }; + + t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) { + throw new RuntimeException(String.format("'%s' tile entity expected", getNbtId())); + } + + if (isLegacy()) { + t = values.get("Text1"); + if (t instanceof StringTag) { + text[0] = ((StringTag) t).getValue(); + } + + t = values.get("Text2"); + if (t instanceof StringTag) { + text[1] = ((StringTag) t).getValue(); + } + + t = values.get("Text3"); + if (t instanceof StringTag) { + text[2] = ((StringTag) t).getValue(); + } + + t = values.get("Text4"); + if (t instanceof StringTag) { + text[3] = ((StringTag) t).getValue(); + } + } else { + CompoundTag frontTextTag = (CompoundTag) values.get("front_text"); + ListTag messagesTag = frontTextTag.getListTag("messages"); + for (int i = 0; i < messagesTag.getValue().size(); i++) { + StringTag tag = (StringTag) messagesTag.getValue().get(i); + text[i] = tag.getValue(); + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java b/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java new file mode 100644 index 0000000..e754fb4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java @@ -0,0 +1,122 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.blocks; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +import java.util.HashMap; +import java.util.Map; + +/** + * A skull block. + */ +public class SkullBlock extends BaseBlock { + + private String owner = ""; // notchian + + /** + * Construct the skull block with a default type of skelton. + * @param state BlockState to set + */ + public SkullBlock(BlockState state) { + super(state); + this.owner = ""; + } + + /** + * Construct the skull block with a given rotation and owner. + * The type is assumed to be player unless owner is null or empty. + * @param blockState BlockState to set + * @param owner name of player + */ + public SkullBlock(BlockState blockState, String owner) { + super(blockState); + this.setOwner(owner); + } + + /** + * Set the skull's owner. Automatically sets type to player if not empty or null. + * @param owner player name to set the skull to + */ + public void setOwner(String owner) { + if (owner == null) { + this.owner = ""; + } else { + if (owner.length() > 16 || owner.isEmpty()) { + this.owner = ""; + } else { + this.owner = owner; + } + } + } + + /** + * Get the skull's owner. Returns null if unset. + * @return player name or null + */ + public String getOwner() { + return owner; + } + + @Override + public boolean hasNbtData() { + return true; + } + + @Override + public String getNbtId() { + return "skull"; + } + + @Override + public CompoundTag getNbtData() { + Map values = new HashMap<>(); + Map inner = new HashMap<>(); + inner.put("Name", new StringTag(owner)); + values.put(DeprecationUtil.getHeadOwnerKey(), new CompoundTag(inner)); + return new CompoundTag(values); + } + + @Override + public void setNbtData(CompoundTag rootTag) { + if (rootTag == null) { + return; + } + + Map values = rootTag.getValue(); + + Tag t; + + t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) { + throw new RuntimeException(String.format("'%s' tile entity expected", getNbtId())); + } + + t = values.get(DeprecationUtil.getHeadOwnerKey()); + if (t instanceof CompoundTag) { + setOwner(((CompoundTag) t).getValue().get("Name").getValue().toString()); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java b/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java new file mode 100644 index 0000000..acb05e0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.blocks; + +import com.sk89q.worldedit.world.NbtValued; + +/** + * Indicates a block that contains extra data identified as an NBT structure. + * Compared to a {@link NbtValued}, tile entity blocks also contain an ID. + * + * @see NbtValued + */ +public interface TileEntityBlock extends NbtValued { + + /** + * Return the name of the title entity ID. + * + * @return tile entity ID, non-null string + */ + String getNbtId(); + +} diff --git a/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java b/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java new file mode 100644 index 0000000..1acb73f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java @@ -0,0 +1,143 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.command.factory.ItemUseFactory; +import com.sk89q.worldedit.command.factory.ReplaceFactory; +import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.factory.ApplyRegion; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.regions.factory.RegionFactory; +import com.sk89q.worldedit.util.TreeGenerator; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; +import net.kyori.text.format.TextDecoration; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandManagerService; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.part.CommandArgument; +import org.enginehub.piston.part.SubCommandPart; + +import java.util.stream.Collectors; + +import static java.util.Objects.requireNonNull; +import static org.enginehub.piston.part.CommandParts.arg; + +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class ApplyBrushCommands { + + private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("shape"), TranslatableComponent.of("worldedit.brush.apply.shape")) + .defaultsTo(ImmutableList.of()) + .ofTypes(ImmutableList.of(Key.of(RegionFactory.class))) + .build(); + + private static final CommandArgument RADIUS = arg(TranslatableComponent.of("radius"), TranslatableComponent.of("worldedit.brush.apply.radius")) + .defaultsTo(ImmutableList.of("5")) + .ofTypes(ImmutableList.of(Key.of(double.class))) + .build(); + + public static void register(CommandManagerService service, CommandManager commandManager, CommandRegistrationHandler registration) { + commandManager.register("apply", builder -> { + builder.description(TranslatableComponent.of("worldedit.brush.apply.description")); + builder.action(org.enginehub.piston.Command.Action.NULL_ACTION); + + CommandManager manager = service.newCommandManager(); + registration.register( + manager, + ApplyBrushCommandsRegistration.builder(), + new ApplyBrushCommands() + ); + + builder.condition(new PermissionCondition(ImmutableSet.of("worldedit.brush.apply"))); + + builder.addParts(REGION_FACTORY, RADIUS); + builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TranslatableComponent.of("worldedit.brush.apply.type")) + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() + .build()); + }); + } + + private void setApplyBrush(CommandParameters parameters, Player player, LocalSession localSession, + Contextual generatorFactory) throws WorldEditException { + double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class)); + RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class); + BrushCommands.setOperationBasedBrush(player, localSession, radius, + new ApplyRegion(generatorFactory), regionFactory, "worldedit.brush.apply"); + } + + @Command( + name = "forest", + desc = "Plant trees" + ) + public void forest(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The type of tree to plant") + TreeGenerator.TreeType type) throws WorldEditException { + setApplyBrush(parameters, player, localSession, new TreeGeneratorFactory(type)); + } + + @Command( + name = "item", + desc = "Use an item" + ) + @CommandPermissions("worldedit.brush.item") + public void item(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The type of item to use") + BaseItem item, + @Arg(desc = "The direction in which the item will be applied", def = "up") + @Direction(includeDiagonals = true) + com.sk89q.worldedit.util.Direction direction) throws WorldEditException { + player.print(TextComponent.builder().append("WARNING: ", TextColor.RED, TextDecoration.BOLD) + .append(TranslatableComponent.of("worldedit.brush.apply.item.warning")).build()); + setApplyBrush(parameters, player, localSession, new ItemUseFactory(item, direction)); + } + + @Command( + name = "set", + desc = "Place a block" + ) + public void set(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The pattern of blocks to use") + Pattern pattern) throws WorldEditException { + setApplyBrush(parameters, player, localSession, new ReplaceFactory(pattern)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java new file mode 100644 index 0000000..001e415 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -0,0 +1,205 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.RegionMaskingFilter; +import com.sk89q.worldedit.function.biome.BiomeReplace; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.component.TextUtils; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.HoverEvent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; + +/** + * Implements biome-related commands such as "/biomelist". + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class BiomeCommands { + + /** + * Create a new instance. + */ + public BiomeCommands() { + } + + @Command( + name = "biomelist", + aliases = { "biomels" }, + desc = "Gets all biomes available." + ) + @CommandPermissions("worldedit.biome.list") + public void biomeList(Actor actor, + @ArgFlag(name = 'p', desc = "Page number.", def = "1") + int page) { + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> { + BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); + + PaginationBox paginationBox = PaginationBox.fromComponents("Available Biomes", "/biomelist -p %page%", + BiomeType.REGISTRY.values().stream() + .map(biomeType -> TextComponent.builder() + .append(biomeType.getId()) + .append(" (") + .append(biomeRegistry.getRichName(biomeType)) + .append(")") + .build()) + .collect(Collectors.toList())); + return paginationBox.create(page); + }, (Component) null); + } + + @Command( + name = "biomeinfo", + desc = "Get the biome of the targeted block.", + descFooter = "By default, uses all blocks in your selection." + ) + @CommandPermissions("worldedit.biome.info") + public void biomeInfo(Actor actor, World world, LocalSession session, + @Switch(name = 't', desc = "Use the block you are looking at.") + boolean useLineOfSight, + @Switch(name = 'p', desc = "Use the block you are currently in.") + boolean usePosition) throws WorldEditException { + BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); + Set biomes = new HashSet<>(); + String messageKey; + + if (useLineOfSight) { + if (actor instanceof Player) { + Location blockPosition = ((Player) actor).getBlockTrace(300); + if (blockPosition == null) { + actor.printError(TranslatableComponent.of("worldedit.raytrace.noblock")); + return; + } + + BiomeType biome = world.getBiome(blockPosition.toVector().toBlockPoint()); + biomes.add(biome); + + messageKey = "worldedit.biomeinfo.lineofsight"; + } else { + actor.printError(TranslatableComponent.of("worldedit.raytrace.require-player")); + return; + } + } else if (usePosition) { + if (actor instanceof Locatable) { + BiomeType biome = world.getBiome(((Locatable) actor).getLocation().toVector().toBlockPoint()); + biomes.add(biome); + + messageKey = "worldedit.biomeinfo.position"; + } else { + actor.printError(TranslatableComponent.of("worldedit.biomeinfo.not-locatable")); + return; + } + } else { + Region region = session.getSelection(world); + + for (BlockVector3 pt : region) { + biomes.add(world.getBiome(pt)); + } + + messageKey = "worldedit.biomeinfo.selection"; + } + + List components = biomes.stream().map(biome -> + biomeRegistry.getRichName(biome).hoverEvent( + HoverEvent.showText(TextComponent.of(biome.getId())) + ) + ).collect(Collectors.toList()); + actor.printInfo(TranslatableComponent.of(messageKey, TextUtils.join(components, TextComponent.of(", ")))); + } + + @Command( + name = "/setbiome", + desc = "Sets the biome of your current block or region.", + descFooter = "By default, uses all the blocks in your selection" + ) + @Logging(REGION) + @CommandPermissions("worldedit.biome.set") + public void setBiome(Actor actor, World world, LocalSession session, EditSession editSession, + @Arg(desc = "Biome type.") BiomeType target, + @Switch(name = 'p', desc = "Use your current position") + boolean atPosition) throws WorldEditException { + Region region; + Mask mask = editSession.getMask(); + + if (atPosition) { + if (actor instanceof Locatable) { + final BlockVector3 pos = ((Locatable) actor).getLocation().toVector().toBlockPoint(); + region = new CuboidRegion(pos, pos); + } else { + actor.printError(TranslatableComponent.of("worldedit.setbiome.not-locatable")); + return; + } + } else { + region = session.getSelection(world); + } + + RegionFunction replace = new BiomeReplace(editSession, target); + if (mask != null) { + replace = new RegionMaskingFilter(mask, replace); + } + RegionVisitor visitor = new RegionVisitor(region, replace); + Operations.completeLegacy(visitor); + + actor.printInfo(TranslatableComponent.of( + "worldedit.setbiome.changed", + TextComponent.of(visitor.getAffected()) + ) + .append(TextComponent.newline()) + .append(TranslatableComponent.of("worldedit.setbiome.warning"))); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java new file mode 100644 index 0000000..1e00cd9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -0,0 +1,534 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.argument.HeightConverter; +import com.sk89q.worldedit.command.factory.ReplaceFactory; +import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.command.tool.brush.ButcherBrush; +import com.sk89q.worldedit.command.tool.brush.ClipboardBrush; +import com.sk89q.worldedit.command.tool.brush.CylinderBrush; +import com.sk89q.worldedit.command.tool.brush.GravityBrush; +import com.sk89q.worldedit.command.tool.brush.HollowCylinderBrush; +import com.sk89q.worldedit.command.tool.brush.HollowSphereBrush; +import com.sk89q.worldedit.command.tool.brush.ImageHeightmapBrush; +import com.sk89q.worldedit.command.tool.brush.OperationFactoryBrush; +import com.sk89q.worldedit.command.tool.brush.SmoothBrush; +import com.sk89q.worldedit.command.tool.brush.SphereBrush; +import com.sk89q.worldedit.command.util.AsyncCommandBuilder; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.CreatureButcher; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.factory.ApplyLayer; +import com.sk89q.worldedit.function.factory.ApplyRegion; +import com.sk89q.worldedit.function.factory.BiomeFactory; +import com.sk89q.worldedit.function.factory.Deform; +import com.sk89q.worldedit.function.factory.Paint; +import com.sk89q.worldedit.function.factory.Snow; +import com.sk89q.worldedit.function.mask.BlockTypeMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.ClipboardMask; +import com.sk89q.worldedit.internal.annotation.VertHeight; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.factory.CylinderRegionFactory; +import com.sk89q.worldedit.regions.factory.RegionFactory; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.session.request.RequestExtent; +import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.asset.AssetLoadTask; +import com.sk89q.worldedit.util.asset.AssetLoader; +import com.sk89q.worldedit.util.asset.holder.ImageHeightmap; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockTypes; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Commands to set brush shape. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class BrushCommands { + + private final WorldEdit worldEdit; + + private static final Component UNBIND_COMMAND_COMPONENT = TextComponent.builder("/brush unbind", TextColor.AQUA) + .clickEvent(ClickEvent.suggestCommand("/brush unbind")) + .build(); + + /** + * Create a new instance. + * + * @param worldEdit reference to WorldEdit + */ + public BrushCommands(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + + @Command( + name = "none", + aliases = "unbind", + desc = "Unbind a bound brush from your current item" + ) + void none(Player player, LocalSession session) throws WorldEditException { + ToolCommands.setToolNone(player, session, true); + } + + @Command( + name = "sphere", + aliases = { "s" }, + desc = "Choose the sphere brush" + ) + @CommandPermissions("worldedit.brush.sphere") + public void sphereBrush(Player player, LocalSession session, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern, + @Arg(desc = "The radius of the sphere", def = "2") + double radius, + @Switch(name = 'h', desc = "Create hollow spheres instead") + boolean hollow) throws WorldEditException { + worldEdit.checkMaxBrushRadius(radius); + + BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + tool.setFill(pattern); + tool.setSize(radius); + + if (hollow) { + tool.setBrush(new HollowSphereBrush(), "worldedit.brush.sphere"); + } else { + tool.setBrush(new SphereBrush(), "worldedit.brush.sphere"); + } + + player.printInfo(TranslatableComponent.of("worldedit.brush.sphere.equip", TextComponent.of(String.format("%.0f", radius)))); + ToolCommands.sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); + } + + @Command( + name = "cylinder", + aliases = { "cyl", "c" }, + desc = "Choose the cylinder brush" + ) + @CommandPermissions("worldedit.brush.cylinder") + public void cylinderBrush(Player player, LocalSession session, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern, + @Arg(desc = "The radius of the cylinder", def = "2") + double radius, + @Arg(desc = "The height of the cylinder", def = "1") + int height, + @Switch(name = 'h', desc = "Create hollow cylinders instead") + boolean hollow) throws WorldEditException { + worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius(height); + + BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + tool.setFill(pattern); + tool.setSize(radius); + + if (hollow) { + tool.setBrush(new HollowCylinderBrush(height), "worldedit.brush.cylinder"); + } else { + tool.setBrush(new CylinderBrush(height), "worldedit.brush.cylinder"); + } + + player.printInfo(TranslatableComponent.of("worldedit.brush.cylinder.equip", TextComponent.of((int) radius), TextComponent.of(height))); + ToolCommands.sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); + } + + @Command( + name = "clipboard", + aliases = { "copy" }, + desc = "Choose the clipboard brush" + ) + @CommandPermissions("worldedit.brush.clipboard") + public void clipboardBrush(Player player, LocalSession session, + @Switch(name = 'a', desc = "Don't paste air from the clipboard") + boolean ignoreAir, + @Switch(name = 'o', desc = "Paste starting at the target location, instead of centering on it") + boolean usingOrigin, + @Switch(name = 'e', desc = "Paste entities if available") + boolean pasteEntities, + @Switch(name = 'b', desc = "Paste biomes if available") + boolean pasteBiomes, + @ArgFlag(name = 'm', desc = "Skip blocks matching this mask in the clipboard") + @ClipboardMask + Mask sourceMask) throws WorldEditException { + ClipboardHolder holder = session.getClipboard(); + + Clipboard clipboard = holder.getClipboard(); + ClipboardHolder newHolder = new ClipboardHolder(clipboard); + newHolder.setTransform(holder.getTransform()); + + BlockVector3 size = clipboard.getDimensions(); + + worldEdit.checkMaxBrushRadius(size.getBlockX() / 2D - 1); + worldEdit.checkMaxBrushRadius(size.getBlockY() / 2D - 1); + worldEdit.checkMaxBrushRadius(size.getBlockZ() / 2D - 1); + + BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + tool.setBrush(new ClipboardBrush(newHolder, ignoreAir, usingOrigin, pasteEntities, pasteBiomes, sourceMask), "worldedit.brush.clipboard"); + + player.printInfo(TranslatableComponent.of("worldedit.brush.clipboard.equip")); + ToolCommands.sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); + } + + @Command( + name = "smooth", + desc = "Choose the terrain softener brush", + descFooter = "Example: '/brush smooth 2 4 grass_block,dirt,stone'" + ) + @CommandPermissions("worldedit.brush.smooth") + public void smoothBrush(Player player, LocalSession session, + @Arg(desc = "The radius to sample for softening", def = "2") + double radius, + @Arg(desc = "The number of iterations to perform", def = "4") + int iterations, + @Arg(desc = "The mask of blocks to use for the heightmap", def = "") + Mask mask) throws WorldEditException { + worldEdit.checkMaxBrushRadius(radius); + + BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + tool.setSize(radius); + tool.setBrush(new SmoothBrush(iterations, mask), "worldedit.brush.smooth"); + + player.printInfo(TranslatableComponent.of( + "worldedit.brush.smooth.equip", + TextComponent.of((int) radius), + TextComponent.of(iterations), + TextComponent.of(mask == null ? "any block" : "filter") + )); + ToolCommands.sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); + } + + @Command( + name = "extinguish", + aliases = { "ex" }, + desc = "Shortcut fire extinguisher brush" + ) + @CommandPermissions("worldedit.brush.ex") + public void extinguishBrush(Player player, LocalSession session, + @Arg(desc = "The radius to extinguish", def = "5") + double radius) throws WorldEditException { + worldEdit.checkMaxBrushRadius(radius); + + BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + tool.setFill(BlockTypes.AIR.getDefaultState()); + tool.setSize(radius); + tool.setMask(new BlockTypeMask(new RequestExtent(), BlockTypes.FIRE)); + tool.setBrush(new SphereBrush(), "worldedit.brush.ex"); + + player.printInfo(TranslatableComponent.of("worldedit.brush.extinguish.equip", TextComponent.of((int) radius))); + ToolCommands.sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); + } + + @Command( + name = "gravity", + aliases = { "grav" }, + desc = "Gravity brush, simulates the effect of gravity" + ) + @CommandPermissions("worldedit.brush.gravity") + public void gravityBrush(Player player, LocalSession session, + @Arg(desc = "The radius to apply gravity in", def = "5") + double radius, + @ArgFlag( + name = 'h', + desc = "Affect blocks between the given height, " + + "upwards and downwards, " + + "rather than the target location Y + radius", + def = HeightConverter.DEFAULT_VALUE + ) + @VertHeight + Integer height) throws WorldEditException { + worldEdit.checkMaxBrushRadius(radius); + + BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + tool.setSize(radius); + tool.setBrush(new GravityBrush(height), "worldedit.brush.gravity"); + + player.printInfo(TranslatableComponent.of("worldedit.brush.gravity.equip", TextComponent.of((int) radius))); + ToolCommands.sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); + } + + @Command( + name = "butcher", + aliases = { "kill" }, + desc = "Butcher brush, kills mobs within a radius" + ) + @CommandPermissions("worldedit.brush.butcher") + public void butcherBrush(Player player, LocalSession session, + @Arg(desc = "Radius to kill mobs in", def = "5") + double radius, + @Switch(name = 'p', desc = "Also kill pets") + boolean killPets, + @Switch(name = 'n', desc = "Also kill NPCs") + boolean killNpcs, + @Switch(name = 'g', desc = "Also kill golems") + boolean killGolems, + @Switch(name = 'a', desc = "Also kill animals") + boolean killAnimals, + @Switch(name = 'b', desc = "Also kill ambient mobs") + boolean killAmbient, + @Switch(name = 't', desc = "Also kill mobs with name tags") + boolean killWithName, + @Switch(name = 'f', desc = "Also kill all friendly mobs (Applies the flags `-abgnpt`)") + boolean killFriendly, + @Switch(name = 'r', desc = "Also destroy armor stands") + boolean killArmorStands, + @Switch(name = 'w', desc = "Also kill water mobs") + boolean killWater) throws WorldEditException { + LocalConfiguration config = worldEdit.getConfiguration(); + + double maxRadius = config.maxBrushRadius; + // hmmmm not horribly worried about this because -1 is still rather efficient, + // the problem arises when butcherMaxRadius is some really high number but not infinite + // - original idea taken from https://github.com/sk89q/worldedit/pull/198#issuecomment-6463108 + if (player.hasPermission("worldedit.butcher")) { + maxRadius = Math.max(config.maxBrushRadius, config.butcherMaxRadius); + } + if (radius > maxRadius) { + player.printError(TranslatableComponent.of("worldedit.brush.radius-too-large", TextComponent.of(maxRadius))); + return; + } + + CreatureButcher flags = new CreatureButcher(player); + flags.or(CreatureButcher.Flags.FRIENDLY, killFriendly); // No permission check here. Flags will instead be filtered by the subsequent calls. + flags.or(CreatureButcher.Flags.PETS, killPets, "worldedit.butcher.pets"); + flags.or(CreatureButcher.Flags.NPCS, killNpcs, "worldedit.butcher.npcs"); + flags.or(CreatureButcher.Flags.GOLEMS, killGolems, "worldedit.butcher.golems"); + flags.or(CreatureButcher.Flags.ANIMALS, killAnimals, "worldedit.butcher.animals"); + flags.or(CreatureButcher.Flags.AMBIENT, killAmbient, "worldedit.butcher.ambient"); + flags.or(CreatureButcher.Flags.TAGGED, killWithName, "worldedit.butcher.tagged"); + flags.or(CreatureButcher.Flags.ARMOR_STAND, killArmorStands, "worldedit.butcher.armorstands"); + flags.or(CreatureButcher.Flags.WATER, killWater, "worldedit.butcher.water"); + + BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + tool.setSize(radius); + tool.setBrush(new ButcherBrush(flags), "worldedit.brush.butcher"); + + player.printInfo(TranslatableComponent.of("worldedit.brush.butcher.equip", TextComponent.of((int) radius))); + ToolCommands.sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); + } + + @Command( + name = "heightmap", + desc = "Heightmap brush, raises or lowers terrain using an image heightmap" + ) + @CommandPermissions("worldedit.brush.heightmap") + void heightmapBrush(Player player, LocalSession session, + @Arg(desc = "The name of the image") + String imageName, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Arg(desc = "The intensity of the brush", def = "5") + double intensity, + @Switch(name = 'e', desc = "Erase blocks instead of filling them") + boolean erase, + @Switch(name = 'f', desc = "Don't change blocks above the selected height") + boolean flatten, + @Switch(name = 'r', desc = "Randomizes the brush's height slightly.") + boolean randomize) throws WorldEditException { + Optional> loader = worldEdit.getAssetLoaders().getAssetLoader(ImageHeightmap.class, imageName); + + if (loader.isPresent()) { + worldEdit.checkMaxBrushRadius(radius); + BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + + AssetLoadTask task = new AssetLoadTask<>(loader.get(), imageName); + AsyncCommandBuilder.wrap(task, player) + .registerWithSupervisor(worldEdit.getSupervisor(), "Loading asset " + imageName) + .setDelayMessage(TranslatableComponent.of("worldedit.asset.load.loading")) + .setWorkingMessage(TranslatableComponent.of("worldedit.asset.load.still-loading")) + .onSuccess(TranslatableComponent.of("worldedit.brush.heightmap.equip", TextComponent.of((int) radius)), heightmap -> { + tool.setSize(radius); + tool.setBrush(new ImageHeightmapBrush(heightmap, intensity, erase, flatten, randomize), "worldedit.brush.heightmap"); + ToolCommands.sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); + }) + .onFailure(TranslatableComponent.of("worldedit.asset.load.failed"), worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter()) + .buildAndExec(worldEdit.getExecutorService()); + } else { + player.printError(TranslatableComponent.of("worldedit.brush.heightmap.unknown", TextComponent.of(imageName))); + } + } + + @Command( + name = "deform", + desc = "Deform brush, applies an expression to an area" + ) + @CommandPermissions("worldedit.brush.deform") + public void deform(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory shape, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Arg(desc = "Expression to apply", def = "y-=0.2") + String expression, + @Switch(name = 'r', desc = "Use the game's coordinate origin") + boolean useRawCoords, + @Switch(name = 'o', desc = "Use the placement position as the origin") + boolean usePlacement) throws WorldEditException { + Deform deform = new Deform(expression); + if (useRawCoords) { + deform.setMode(Deform.Mode.RAW_COORD); + } else if (usePlacement) { + deform.setMode(Deform.Mode.OFFSET); + deform.setOffset(localSession.getPlacementPosition(player).toVector3()); + } + setOperationBasedBrush(player, localSession, radius, + deform, shape, "worldedit.brush.deform"); + } + + @Command( + name = "set", + desc = "Set brush, sets all blocks in the area" + ) + @CommandPermissions("worldedit.brush.set") + public void set(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory shape, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new ApplyRegion(new ReplaceFactory(pattern)), shape, "worldedit.brush.set"); + } + + @Command( + name = "forest", + desc = "Forest brush, creates a forest in the area" + ) + @CommandPermissions("worldedit.brush.forest") + public void forest(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory shape, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Arg(desc = "The density of the brush", def = "20") + double density, + @Arg(desc = "The type of tree to use") + TreeGenerator.TreeType type) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Paint(new TreeGeneratorFactory(type), density / 100), shape, "worldedit.brush.forest"); + } + + @Command( + name = "raise", + desc = "Raise brush, raise all blocks by one" + ) + @CommandPermissions("worldedit.brush.raise") + public void raise(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory shape, + @Arg(desc = "The size of the brush", def = "5") + double radius) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Deform("y-=1", Deform.Mode.RAW_COORD), shape, "worldedit.brush.raise"); + } + + @Command( + name = "lower", + desc = "Lower brush, lower all blocks by one" + ) + @CommandPermissions("worldedit.brush.lower") + public void lower(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory shape, + @Arg(desc = "The size of the brush", def = "5") + double radius) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Deform("y+=1", Deform.Mode.RAW_COORD), shape, "worldedit.brush.lower"); + } + + @Command( + name = "snow", + desc = "Snow brush, sets snow in the area" + ) + @CommandPermissions("worldedit.brush.snow") + public void snow(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory shape, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Switch(name = 's', desc = "Whether to stack snow") + boolean stack) throws WorldEditException { + + if (shape instanceof CylinderRegionFactory) { + shape = new CylinderRegionFactory(radius); + } + + setOperationBasedBrush(player, localSession, radius, + new ApplyLayer(new Snow(stack)), shape, "worldedit.brush.snow"); + } + + @Command( + name = "biome", + desc = "Biome brush, sets biomes in the area" + ) + @CommandPermissions("worldedit.brush.biome") + public void biome(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory shape, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Arg(desc = "The biome type") + BiomeType biomeType) throws WorldEditException { + + setOperationBasedBrush(player, localSession, radius, + new ApplyRegion(new BiomeFactory(biomeType)), shape, "worldedit.brush.biome"); + player.printInfo(TranslatableComponent.of("worldedit.setbiome.warning")); + } + + static void setOperationBasedBrush(Player player, LocalSession session, double radius, + Contextual factory, + RegionFactory shape, + String permission) throws WorldEditException { + WorldEdit.getInstance().checkMaxBrushRadius(radius); + BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + tool.setSize(radius); + tool.setFill(null); + tool.setBrush(new OperationFactoryBrush(factory, shape, session), permission); + + player.printInfo(TranslatableComponent.of("worldedit.brush.operation.equip", TextComponent.of(factory.toString()))); + ToolCommands.sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java new file mode 100644 index 0000000..de3ae18 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -0,0 +1,204 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.gson.JsonIOException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.anvil.ChunkDeleter; +import com.sk89q.worldedit.internal.anvil.ChunkDeletionInfo; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.storage.LegacyChunkStore; +import com.sk89q.worldedit.world.storage.McRegionChunkStore; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.exception.StopExecutionException; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; +import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; + +/** + * Commands for working with chunks. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class ChunkCommands { + + private final WorldEdit worldEdit; + + public ChunkCommands(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + + @Command( + name = "chunkinfo", + desc = "Get information about the chunk you're inside" + ) + @CommandPermissions("worldedit.chunkinfo") + public void chunkInfo(Player player) { + Location pos = player.getBlockLocation(); + int chunkX = (int) Math.floor(pos.getBlockX() / 16.0); + int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0); + + final BlockVector2 chunkPos = BlockVector2.at(chunkX, chunkZ); + player.printInfo(TranslatableComponent.of("worldedit.chunkinfo.chunk", TextComponent.of(chunkX), TextComponent.of(chunkZ))); + player.printInfo(TranslatableComponent.of("worldedit.chunkinfo.old-filename", TextComponent.of(LegacyChunkStore.getFilename(chunkPos)))); + player.printInfo(TranslatableComponent.of("worldedit.chunkinfo.mcregion-filename", TextComponent.of(McRegionChunkStore.getFilename(chunkPos)))); + } + + @Command( + name = "listchunks", + desc = "List chunks that your selection includes" + ) + @CommandPermissions("worldedit.listchunks") + public void listChunks(Actor actor, World world, LocalSession session, + @ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException { + final Region region = session.getSelection(world); + + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, + () -> new ChunkListPaginationBox(region).create(page), + TranslatableComponent.of( + "worldedit.listchunks.listfor", + TextComponent.of(actor.getName()) + )); + } + + @Command( + name = "delchunks", + desc = "Delete chunks that your selection includes" + ) + @CommandPermissions("worldedit.delchunks") + @Logging(REGION) + public void deleteChunks(Actor actor, World world, LocalSession session, + @ArgFlag(name = 'o', desc = "Only delete chunks older than the specified time.") + ZonedDateTime beforeTime) throws WorldEditException { + Path worldDir = world.getStoragePath(); + if (worldDir == null) { + throw new StopExecutionException(TextComponent.of("Couldn't find world folder for this world.")); + } + + Path chunkPath = worldEdit.getWorkingDirectoryPath(DELCHUNKS_FILE_NAME); + ChunkDeletionInfo currentInfo = null; + if (Files.exists(chunkPath)) { + try { + currentInfo = ChunkDeleter.readInfo(chunkPath); + } catch (IOException e) { + throw new StopExecutionException(TextComponent.of("Error reading existing chunk file.")); + } + } + if (currentInfo == null) { + currentInfo = new ChunkDeletionInfo(); + currentInfo.batches = new ArrayList<>(); + } + + ChunkDeletionInfo.ChunkBatch newBatch = new ChunkDeletionInfo.ChunkBatch(); + newBatch.worldPath = worldDir.toAbsolutePath().normalize().toString(); + newBatch.backup = true; + final Region selection = session.getSelection(world); + if (selection instanceof CuboidRegion) { + newBatch.minChunk = selection.getMinimumPoint().shr(4).toBlockVector2(); + newBatch.maxChunk = selection.getMaximumPoint().shr(4).toBlockVector2(); + } else { + // this has a possibility to OOM for very large selections still + Set chunks = selection.getChunks(); + newBatch.chunks = new ArrayList<>(chunks); + } + if (beforeTime != null) { + newBatch.deletionPredicates = new ArrayList<>(); + ChunkDeletionInfo.DeletionPredicate timePred = new ChunkDeletionInfo.DeletionPredicate(); + timePred.property = "modification"; + timePred.comparison = "<"; + timePred.value = String.valueOf((int) beforeTime.toOffsetDateTime().toEpochSecond()); + newBatch.deletionPredicates.add(timePred); + } + currentInfo.batches.add(newBatch); + + try { + ChunkDeleter.writeInfo(currentInfo, chunkPath); + } catch (IOException | JsonIOException e) { + throw new StopExecutionException(TextComponent.of("Failed to write chunk list: " + e.getMessage())); + } + + actor.print(TextComponent.of( + String.format("%d chunk(s) have been marked for deletion the next time the server starts.", + newBatch.getChunkCount()) + )); + if (currentInfo.batches.size() > 1) { + actor.printDebug(TextComponent.of( + String.format("%d chunks total marked for deletion. (May have overlaps).", + currentInfo.batches.stream().mapToInt(ChunkDeletionInfo.ChunkBatch::getChunkCount).sum()) + )); + } + actor.print(TextComponent.of("You can mark more chunks for deletion, or to stop now, run: ", TextColor.LIGHT_PURPLE) + .append(TextComponent.of("/stop", TextColor.AQUA) + .clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop")))); + } + + private static class ChunkListPaginationBox extends PaginationBox { + //private final Region region; + private final List chunks; + + ChunkListPaginationBox(Region region) { + super("Selected Chunks", "/listchunks -p %page%"); + // TODO make efficient/streamable/calculable implementations of this + // for most region types, so we can just store the region and random-access get one page of chunks + // (this is non-trivial for some types of selections...) + //this.region = region.clone(); + this.chunks = new ArrayList<>(region.getChunks()); + } + + @Override + public Component getComponent(int number) { + return TextComponent.of(chunks.get(number).toString()); + } + + @Override + public int getComponentsSize() { + return chunks.size(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java new file mode 100644 index 0000000..9c38683 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -0,0 +1,264 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.common.collect.Lists; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.block.BlockReplace; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.ClipboardMask; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.annotation.Selection; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.ExtendingCuboidRegionSelector; +import com.sk89q.worldedit.session.ClipboardHolder; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; + +import java.util.List; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; + +/** + * Clipboard commands. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class ClipboardCommands { + + /** + * Throws if the region would allocate a clipboard larger than the block change limit. + * + * @param region The region to check + * @param session The session + * @throws MaxChangedBlocksException if the volume exceeds the limit + */ + private void checkRegionBounds(Region region, LocalSession session) throws MaxChangedBlocksException { + int limit = session.getBlockChangeLimit(); + if (limit >= 0 && region.getBoundingBox().getVolume() >= limit) { + throw new MaxChangedBlocksException(limit); + } + } + + @Command( + name = "/copy", + desc = "Copy the selection to the clipboard" + ) + @CommandPermissions("worldedit.clipboard.copy") + public void copy(Actor actor, LocalSession session, EditSession editSession, + @Selection Region region, + @Switch(name = 'e', desc = "Also copy entities") + boolean copyEntities, + @Switch(name = 'b', desc = "Also copy biomes") + boolean copyBiomes, + @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air") + Mask mask) throws WorldEditException { + checkRegionBounds(region, session); + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOrigin(session.getPlacementPosition(actor)); + ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); + copy.setCopyingEntities(copyEntities); + copy.setCopyingBiomes(copyBiomes); + if (mask != null) { + copy.setSourceMask(mask); + } + Operations.completeLegacy(copy); + session.setClipboard(new ClipboardHolder(clipboard)); + + copy.getStatusMessages().forEach(actor::print); + } + + @Command( + name = "/cut", + desc = "Cut the selection to the clipboard" + ) + @CommandPermissions("worldedit.clipboard.cut") + @Logging(REGION) + public void cut(Actor actor, LocalSession session, EditSession editSession, + @Selection Region region, + @Arg(desc = "Pattern to leave in place of the selection", def = "air") + Pattern leavePattern, + @Switch(name = 'e', desc = "Also cut entities") + boolean copyEntities, + @Switch(name = 'b', desc = "Also copy biomes, source biomes are unaffected") + boolean copyBiomes, + @ArgFlag(name = 'm', desc = "Set the exclude mask, non-matching blocks become air") + Mask mask) throws WorldEditException { + checkRegionBounds(region, session); + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOrigin(session.getPlacementPosition(actor)); + ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); + copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); + copy.setCopyingEntities(copyEntities); + copy.setRemovingEntities(true); + copy.setCopyingBiomes(copyBiomes); + if (mask != null) { + copy.setSourceMask(mask); + } + Operations.completeLegacy(copy); + session.setClipboard(new ClipboardHolder(clipboard)); + + copy.getStatusMessages().forEach(actor::print); + } + + @Command( + name = "/paste", + desc = "Paste the clipboard's contents" + ) + @CommandPermissions("worldedit.clipboard.paste") + @Logging(PLACEMENT) + public void paste(Actor actor, World world, LocalSession session, EditSession editSession, + @Switch(name = 'a', desc = "Skip air blocks") + boolean ignoreAirBlocks, + @Switch(name = 'o', desc = "Paste at the original position") + boolean atOrigin, + @Switch(name = 's', desc = "Select the region after pasting") + boolean selectPasted, + @Switch(name = 'n', desc = "No paste, select only. (Implies -s)") + boolean onlySelect, + @Switch(name = 'e', desc = "Paste entities if available") + boolean pasteEntities, + @Switch(name = 'b', desc = "Paste biomes if available") + boolean pasteBiomes, + @ArgFlag(name = 'm', desc = "Only paste blocks matching this mask") + @ClipboardMask + Mask sourceMask) throws WorldEditException { + + ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); + Region region = clipboard.getRegion(); + List messages = Lists.newArrayList(); + + BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(actor); + if (!onlySelect) { + Operation operation = holder + .createPaste(editSession) + .to(to) + .ignoreAirBlocks(ignoreAirBlocks) + .copyBiomes(pasteBiomes) + .copyEntities(pasteEntities) + .maskSource(sourceMask) + .build(); + Operations.completeLegacy(operation); + messages.addAll(Lists.newArrayList(operation.getStatusMessages())); + } + + if (selectPasted || onlySelect) { + BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin()); + Vector3 realTo = to.toVector3().add(holder.getTransform().apply(clipboardOffset.toVector3())); + Vector3 max = realTo.add(holder.getTransform().apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3())); + final CuboidRegionSelector selector; + if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) { + selector = new ExtendingCuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); + } else { + selector = new CuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); + } + session.setRegionSelector(world, selector); + selector.learnChanges(); + selector.explainRegionAdjust(actor, session); + } + + if (onlySelect) { + actor.printInfo(TranslatableComponent.of("worldedit.paste.selected")); + } else { + actor.printInfo(TranslatableComponent.of("worldedit.paste.pasted", TextComponent.of(to.toString()))); + } + messages.forEach(actor::print); + } + + @Command( + name = "/rotate", + desc = "Rotate the contents of the clipboard", + descFooter = "Non-destructively rotate the contents of the clipboard.\n" + + "Angles are provided in degrees and a positive angle will result in a clockwise rotation. " + + "Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n" + ) + @CommandPermissions("worldedit.clipboard.rotate") + public void rotate(Actor actor, LocalSession session, + @Arg(desc = "Amount to rotate on the y-axis") + double rotateY, + @Arg(desc = "Amount to rotate on the x-axis", def = "0") + double rotateX, + @Arg(desc = "Amount to rotate on the z-axis", def = "0") + double rotateZ) throws WorldEditException { + if (Math.abs(rotateY % 90) > 0.001 + || Math.abs(rotateX % 90) > 0.001 + || Math.abs(rotateZ % 90) > 0.001) { + actor.printDebug(TranslatableComponent.of("worldedit.rotate.no-interpolation")); + } + + ClipboardHolder holder = session.getClipboard(); + AffineTransform transform = new AffineTransform(); + transform = transform.rotateY(-rotateY); + transform = transform.rotateX(-rotateX); + transform = transform.rotateZ(-rotateZ); + holder.setTransform(holder.getTransform().combine(transform)); + actor.printInfo(TranslatableComponent.of("worldedit.rotate.rotated")); + } + + @Command( + name = "/flip", + desc = "Flip the contents of the clipboard across the origin" + ) + @CommandPermissions("worldedit.clipboard.flip") + public void flip(Actor actor, LocalSession session, + @Arg(desc = "The direction to flip, defaults to look direction.", def = Direction.AIM) + @Direction BlockVector3 direction) throws WorldEditException { + ClipboardHolder holder = session.getClipboard(); + AffineTransform transform = new AffineTransform(); + transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3()); + holder.setTransform(holder.getTransform().combine(transform)); + actor.printInfo(TranslatableComponent.of("worldedit.flip.flipped")); + } + + @Command( + name = "clearclipboard", + desc = "Clear your clipboard" + ) + @CommandPermissions("worldedit.clipboard.clear") + public void clearClipboard(Actor actor, LocalSession session) { + session.setClipboard(null); + actor.printInfo(TranslatableComponent.of("worldedit.clearclipboard.cleared")); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java b/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java new file mode 100644 index 0000000..0334863 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java @@ -0,0 +1,158 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.annotation.MultiDirection; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandManagerService; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.part.SubCommandPart; + +import java.util.List; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; +import static com.sk89q.worldedit.internal.command.CommandUtil.requireIV; + +/** + * Extracted from {@link SelectionCommands} to allow importing of {@link Command}. + */ +@CommandContainer +public class ExpandCommands { + + public static void register(CommandRegistrationHandler registration, + CommandManager commandManager, + CommandManagerService commandManagerService) { + // Collect the general expand command + CommandManager collect = commandManagerService.newCommandManager(); + + registration.register( + collect, + ExpandCommandsRegistration.builder(), + new ExpandCommands() + ); + + Command expandBaseCommand = collect.getCommand("/expand") + .orElseThrow(() -> new IllegalStateException("No /expand command")); + + commandManager.register("/expand", command -> { + command.condition(new PermissionCondition(ImmutableSet.of("worldedit.selection.expand"))); + + command.addPart(SubCommandPart.builder( + TranslatableComponent.of("vert"), + TextComponent.of("Vertical expansion sub-command") + ) + .withCommands(ImmutableSet.of(createVertCommand(commandManager))) + .optional() + .build()); + + command.addParts(expandBaseCommand.getParts()); + command.action(expandBaseCommand.getAction()); + command.description(expandBaseCommand.getDescription()); + }); + } + + private static Command createVertCommand(CommandManager commandManager) { + return commandManager.newCommand("vert") + .description(TranslatableComponent.of("worldedit.expand.description.vert")) + .action(parameters -> { + expandVert( + requireIV(Key.of(LocalSession.class), "localSession", parameters), + requireIV(Key.of(Actor.class), "actor", parameters), + requireIV(Key.of(World.class), "world", parameters) + ); + return 1; + }) + .build(); + } + + private static void expandVert(LocalSession session, Actor actor, World world) throws IncompleteRegionException { + Region region = session.getSelection(world); + int height = world.getMaxY() - world.getMinY(); + try { + long oldSize = region.getVolume(); + region.expand( + BlockVector3.at(0, height, 0), + BlockVector3.at(0, -height, 0)); + session.getRegionSelector(world).learnChanges(); + long newSize = region.getVolume(); + session.getRegionSelector(world).explainRegionAdjust(actor, session); + long changeSize = newSize - oldSize; + actor.printInfo( + TranslatableComponent.of("worldedit.expand.expanded.vert", TextComponent.of(changeSize)) + ); + } catch (RegionOperationException e) { + actor.printError(TextComponent.of(e.getMessage())); + } + } + + @org.enginehub.piston.annotation.Command( + name = "/expand", + desc = "Expand the selection area" + ) + @Logging(REGION) + public void expand(Actor actor, World world, LocalSession session, + @Arg(desc = "Amount to expand the selection by, can be `vert` to expand to the whole vertical column") + int amount, + @Arg(desc = "Amount to expand the selection by in the other direction", def = "0") + int reverseAmount, + @Arg(desc = "Direction to expand", def = Direction.AIM) + @MultiDirection + List direction) throws WorldEditException { + Region region = session.getSelection(world); + long oldSize = region.getVolume(); + + if (reverseAmount == 0) { + for (BlockVector3 dir : direction) { + region.expand(dir.multiply(amount)); + } + } else { + for (BlockVector3 dir : direction) { + region.expand(dir.multiply(amount), dir.multiply(-reverseAmount)); + } + } + + session.getRegionSelector(world).learnChanges(); + long newSize = region.getVolume(); + + session.getRegionSelector(world).explainRegionAdjust(actor, session); + + long changeSize = newSize - oldSize; + actor.printInfo(TranslatableComponent.of("worldedit.expand.expanded", TextComponent.of(changeSize))); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java b/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java new file mode 100644 index 0000000..7f588fe --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java @@ -0,0 +1,136 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.transform.BlockTransformExtent; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.math.transform.CombinedTransform; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helper class to 'bake' a transform into a clipboard. + * + *

This class needs a better name and may need to be made more generic.

+ * + * @see Clipboard + * @see Transform + */ +class FlattenedClipboardTransform { + + private final Clipboard original; + private final Transform transform; + + /** + * Create a new instance. + * + * @param original the original clipboard + * @param transform the transform + */ + private FlattenedClipboardTransform(Clipboard original, Transform transform) { + checkNotNull(original); + checkNotNull(transform); + this.original = original; + this.transform = transform; + } + + /** + * Get the transformed region. + * + * @return the transformed region + */ + public Region getTransformedRegion() { + Region region = original.getRegion(); + Vector3 minimum = region.getMinimumPoint().toVector3(); + Vector3 maximum = region.getMaximumPoint().toVector3(); + + Transform transformAround = + new CombinedTransform( + new AffineTransform().translate(original.getOrigin().multiply(-1)), + transform, + new AffineTransform().translate(original.getOrigin())); + + Vector3[] corners = new Vector3[] { + minimum, + maximum, + minimum.withX(maximum.getX()), + minimum.withY(maximum.getY()), + minimum.withZ(maximum.getZ()), + maximum.withX(minimum.getX()), + maximum.withY(minimum.getY()), + maximum.withZ(minimum.getZ()) + }; + + for (int i = 0; i < corners.length; i++) { + corners[i] = transformAround.apply(corners[i]); + } + + Vector3 newMinimum = corners[0]; + Vector3 newMaximum = corners[0]; + + for (int i = 1; i < corners.length; i++) { + newMinimum = newMinimum.getMinimum(corners[i]); + newMaximum = newMaximum.getMaximum(corners[i]); + } + + // After transformation, the points may not really sit on a block, + // so we should expand the region for edge cases + newMinimum = newMinimum.floor(); + newMaximum = newMaximum.ceil(); + + return new CuboidRegion(newMinimum.toBlockPoint(), newMaximum.toBlockPoint()); + } + + /** + * Create an operation to copy from the original clipboard to the given extent. + * + * @param target the target + * @return the operation + */ + public Operation copyTo(Extent target) { + BlockTransformExtent extent = new BlockTransformExtent(original, transform); + ForwardExtentCopy copy = new ForwardExtentCopy(extent, original.getRegion(), original.getOrigin(), target, original.getOrigin()); + copy.setTransform(transform); + if (original.hasBiomes()) { + copy.setCopyingBiomes(true); + } + return copy; + } + + /** + * Create a new instance to bake the transform with. + * + * @param original the original clipboard + * @param transform the transform + * @return a builder + */ + public static FlattenedClipboardTransform transform(Clipboard original, Transform transform) { + return new FlattenedClipboardTransform(original, transform); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java new file mode 100644 index 0000000..b15147b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -0,0 +1,481 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.HookMode; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.internal.command.CommandUtil; +import com.sk89q.worldedit.internal.cui.ServerCUIHandler; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.component.SideEffectBox; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.item.ItemType; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandManagerService; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.Callable; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * General WorldEdit commands. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class GeneralCommands { + + public static void register(CommandRegistrationHandler registration, + CommandManager commandManager, + CommandManagerService commandManagerService, + WorldEdit worldEdit) { + // Collect the tool commands + CommandManager collect = commandManagerService.newCommandManager(); + + registration.register( + collect, + GeneralCommandsRegistration.builder(), + new GeneralCommands(worldEdit) + ); + + + Set commands = collect.getAllCommands() + .collect(Collectors.toSet()); + for (org.enginehub.piston.Command command : commands) { + if (command.getName().equals("/fast")) { + // deprecate to `//perf` + commandManager.register(CommandUtil.deprecate( + command, "//fast duplicates //perf " + + "and will be removed in WorldEdit 8", + GeneralCommands::replaceFastForPerf + )); + continue; + } + + commandManager.register(command); + } + } + + private static Component replaceFastForPerf(org.enginehub.piston.Command oldCmd, + CommandParameters oldParams) { + if (oldParams.getMetadata() == null) { + return CommandUtil.createNewCommandReplacementText("//perf"); + } + ImmutableList args = oldParams.getMetadata().getArguments(); + if (args.isEmpty()) { + return TextComponent.of("There is not yet a replacement for //fast" + + " with no arguments"); + } + String arg0 = args.get(0).toLowerCase(Locale.ENGLISH); + String flipped; + switch (arg0) { + case "on": + flipped = "off"; + break; + case "off": + flipped = "on"; + break; + default: + return TextComponent.of("There is no replacement for //fast " + arg0); + } + return CommandUtil.createNewCommandReplacementText("//perf " + flipped); + } + + private final WorldEdit worldEdit; + + /** + * Create a new instance. + * + * @param worldEdit reference to WorldEdit + */ + public GeneralCommands(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + + @Command( + name = "/limit", + desc = "Modify block change limit" + ) + @CommandPermissions("worldedit.limit") + public void limit(Actor actor, LocalSession session, + @Arg(desc = "The limit to set", def = "") + Integer limit) { + + LocalConfiguration config = worldEdit.getConfiguration(); + boolean mayDisable = actor.hasPermission("worldedit.limit.unrestricted"); + + limit = limit == null ? config.defaultChangeLimit : Math.max(-1, limit); + if (!mayDisable && config.maxChangeLimit > -1) { + if (limit > config.maxChangeLimit) { + actor.printError(TranslatableComponent.of("worldedit.limit.too-high", TextComponent.of(config.maxChangeLimit))); + return; + } + } + + session.setBlockChangeLimit(limit); + Component component = TextComponent.empty().append(TranslatableComponent.of("worldedit.limit.set", TextComponent.of(limit))); + if (limit != config.defaultChangeLimit) { + component.append(TextComponent.space()).append(TranslatableComponent.of("worldedit.limit.return-to-default", TextColor.GRAY)); + } + actor.printInfo(component); + } + + @Command( + name = "/timeout", + desc = "Modify evaluation timeout time." + ) + @CommandPermissions("worldedit.timeout") + public void timeout(Actor actor, LocalSession session, + @Arg(desc = "The timeout time to set", def = "") + Integer limit) { + LocalConfiguration config = worldEdit.getConfiguration(); + boolean mayDisable = actor.hasPermission("worldedit.timeout.unrestricted"); + + limit = limit == null ? config.calculationTimeout : Math.max(-1, limit); + if (!mayDisable && config.maxCalculationTimeout > -1) { + if (limit > config.maxCalculationTimeout) { + actor.printError(TranslatableComponent.of("worldedit.timeout.too-high", TextComponent.of(config.maxCalculationTimeout))); + return; + } + } + + session.setTimeout(limit); + Component component = TextComponent.empty().append(TranslatableComponent.of("worldedit.timeout.set", TextComponent.of(limit))); + if (limit != config.calculationTimeout) { + component.append(TranslatableComponent.of("worldedit.timeout.return-to-default", TextColor.GRAY)); + } + actor.printInfo(component); + } + + @Command( + name = "/fast", + desc = "Toggle fast mode" + ) + @CommandPermissions("worldedit.fast") + @SuppressWarnings("deprecation") + void fast(Actor actor, LocalSession session, + @Arg(desc = "The new fast mode state", def = "") + Boolean fastMode) { + boolean hasFastMode = session.hasFastMode(); + if (fastMode != null && fastMode == hasFastMode) { + actor.printError(TranslatableComponent.of(fastMode ? "worldedit.fast.enabled.already" : "worldedit.fast.disabled.already")); + return; + } + + if (hasFastMode) { + session.setFastMode(false); + actor.printInfo(TranslatableComponent.of("worldedit.fast.disabled")); + } else { + session.setFastMode(true); + actor.printInfo(TranslatableComponent.of("worldedit.fast.enabled")); + } + } + + @Command( + name = "/perf", + desc = "Toggle side effects for performance", + descFooter = "Note that this command is GOING to change in the future." + + " Do not depend on the exact format of this command yet." + ) + @CommandPermissions("worldedit.perf") + void perf(Actor actor, LocalSession session, + @Arg(desc = "The side effect", def = "") + SideEffect sideEffect, + @Arg(desc = "The new side effect state", def = "") + SideEffect.State newState, + @Switch(name = 'h', desc = "Show the info box") + boolean showInfoBox) throws WorldEditException { + if (sideEffect != null) { + SideEffect.State currentState = session.getSideEffectSet().getState(sideEffect); + if (newState != null && newState == currentState) { + if (!showInfoBox) { + actor.printError(TranslatableComponent.of( + "worldedit.perf.sideeffect.already-set", + TranslatableComponent.of(sideEffect.getDisplayName()), + TranslatableComponent.of(newState.getDisplayName()) + )); + } + return; + } + + if (newState != null) { + session.setSideEffectSet(session.getSideEffectSet().with(sideEffect, newState)); + if (!showInfoBox) { + actor.printInfo(TranslatableComponent.of( + "worldedit.perf.sideeffect.set", + TranslatableComponent.of(sideEffect.getDisplayName()), + TranslatableComponent.of(newState.getDisplayName()) + )); + } + } else { + actor.printInfo(TranslatableComponent.of( + "worldedit.perf.sideeffect.get", + TranslatableComponent.of(sideEffect.getDisplayName()), + TranslatableComponent.of(currentState.getDisplayName()) + )); + } + } else if (newState != null) { + SideEffectSet applier = session.getSideEffectSet(); + for (SideEffect sideEffectEntry : SideEffect.values()) { + applier = applier.with(sideEffectEntry, newState); + } + session.setSideEffectSet(applier); + if (!showInfoBox) { + actor.printInfo(TranslatableComponent.of( + "worldedit.perf.sideeffect.set-all", + TranslatableComponent.of(newState.getDisplayName()) + )); + } + } + + if (sideEffect == null || showInfoBox) { + SideEffectBox sideEffectBox = new SideEffectBox(session.getSideEffectSet()); + actor.print(sideEffectBox.create(1)); + } + } + + @Command( + name = "/reorder", + desc = "Sets the reorder mode of WorldEdit" + ) + @CommandPermissions("worldedit.reorder") + public void reorderMode(Actor actor, LocalSession session, + @Arg(desc = "The reorder mode", def = "") + EditSession.ReorderMode reorderMode) { + if (reorderMode == null) { + actor.printInfo(TranslatableComponent.of("worldedit.reorder.current", TextComponent.of(session.getReorderMode().getDisplayName()))); + } else { + session.setReorderMode(reorderMode); + actor.printInfo(TranslatableComponent.of("worldedit.reorder.set", TextComponent.of(session.getReorderMode().getDisplayName()))); + } + } + + @Command( + name = "/drawsel", + desc = "Toggle drawing the current selection" + ) + @CommandPermissions("worldedit.drawsel") + public void drawSelection(Player player, LocalSession session, + @Arg(desc = "The new draw selection state", def = "") + Boolean drawSelection) throws WorldEditException { + if (!WorldEdit.getInstance().getConfiguration().serverSideCUI) { + throw new AuthorizationException(TranslatableComponent.of("worldedit.error.disabled")); + } + boolean useServerCui = session.shouldUseServerCUI(); + if (drawSelection != null && drawSelection == useServerCui) { + player.printError(TranslatableComponent.of("worldedit.drawsel." + (useServerCui ? "enabled" : "disabled") + ".already")); + + return; + } + if (useServerCui) { + session.setUseServerCUI(false); + session.updateServerCUI(player); + player.printInfo(TranslatableComponent.of("worldedit.drawsel.disabled")); + } else { + session.setUseServerCUI(true); + session.updateServerCUI(player); + + int maxSize = ServerCUIHandler.getMaxServerCuiSize(); + player.printInfo(TranslatableComponent.of( + "worldedit.drawsel.enabled", + TextComponent.of(maxSize), + TextComponent.of(maxSize), + TextComponent.of(maxSize) + )); + } + } + + @Command( + name = "/world", + desc = "Sets the world override" + ) + @CommandPermissions("worldedit.world") + public void world(Actor actor, LocalSession session, + @Arg(desc = "The world override", def = "") World world) { + session.setWorldOverride(world); + if (world == null) { + actor.printInfo(TranslatableComponent.of("worldedit.world.remove")); + } else { + actor.printInfo(TranslatableComponent.of("worldedit.world.set", TextComponent.of(world.getId()))); + } + } + + @Command( + name = "/watchdog", + desc = "Changes watchdog hook state.", + descFooter = "This is dependent on platform implementation. " + + "Not all platforms support watchdog hooks, or contain a watchdog." + ) + @CommandPermissions("worldedit.watchdog") + public void watchdog(Actor actor, LocalSession session, + @Arg(desc = "The mode to set the watchdog hook to", def = "") + HookMode hookMode) { + if (WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getWatchdog() == null) { + actor.printError(TranslatableComponent.of("worldedit.watchdog.no-hook")); + return; + } + boolean previousMode = session.isTickingWatchdog(); + if (hookMode != null && (hookMode == HookMode.ACTIVE) == previousMode) { + actor.printError(TranslatableComponent.of(previousMode ? "worldedit.watchdog.active.already" : "worldedit.watchdog.inactive.already")); + return; + } + session.setTickingWatchdog(!previousMode); + actor.printInfo(TranslatableComponent.of(previousMode ? "worldedit.watchdog.inactive" : "worldedit.watchdog.active")); + } + + @Command( + name = "gmask", + aliases = {"/gmask"}, + desc = "Set the global mask" + ) + @CommandPermissions("worldedit.global-mask") + public void gmask(Actor actor, LocalSession session, + @Arg(desc = "The mask to set", def = "") + Mask mask) { + if (mask == null) { + session.setMask(null); + actor.printInfo(TranslatableComponent.of("worldedit.gmask.disabled")); + } else { + session.setMask(mask); + actor.printInfo(TranslatableComponent.of("worldedit.gmask.set")); + } + } + + @Command( + name = "toggleplace", + aliases = {"/toggleplace"}, + desc = "Switch between your position and pos1 for placement" + ) + public void togglePlace(Actor actor, LocalSession session) { + if (!(actor instanceof Locatable)) { + actor.printError(TranslatableComponent.of("worldedit.toggleplace.not-locatable")); + return; + } + if (session.togglePlacementPosition()) { + actor.printInfo(TranslatableComponent.of("worldedit.toggleplace.pos1")); + } else { + actor.printInfo(TranslatableComponent.of("worldedit.toggleplace.player")); + } + } + + @Command( + name = "searchitem", + aliases = {"/searchitem", "/l", "/search"}, + desc = "Search for an item" + ) + @CommandPermissions("worldedit.searchitem") + public void searchItem(Actor actor, + @Switch(name = 'b', desc = "Only search for blocks") + boolean blocksOnly, + @Switch(name = 'i', desc = "Only search for items") + boolean itemsOnly, + @ArgFlag(name = 'p', desc = "Page of results to return", def = "1") + int page, + @Arg(desc = "Search query", variable = true) + List query) { + String search = String.join(" ", query); + if (search.length() <= 2) { + actor.printError(TranslatableComponent.of("worldedit.searchitem.too-short")); + return; + } + if (blocksOnly && itemsOnly) { + actor.printError(TranslatableComponent.of("worldedit.searchitem.either-b-or-i")); + return; + } + + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, new ItemSearcher(search, blocksOnly, itemsOnly, page), + TranslatableComponent.of("worldedit.searchitem.searching")); + } + + private static class ItemSearcher implements Callable { + private final boolean blocksOnly; + private final boolean itemsOnly; + private final String search; + private final int page; + + ItemSearcher(String search, boolean blocksOnly, boolean itemsOnly, int page) { + this.blocksOnly = blocksOnly; + this.itemsOnly = itemsOnly; + this.search = search; + this.page = page; + } + + @Override + public Component call() throws Exception { + String command = "/searchitem " + (blocksOnly ? "-b " : "") + (itemsOnly ? "-i " : "") + "-p %page% " + search; + Map results = new TreeMap<>(); + String idMatch = search.replace(' ', '_'); + String nameMatch = search.toLowerCase(Locale.ROOT); + for (ItemType searchType : ItemType.REGISTRY) { + if (blocksOnly && !searchType.hasBlockType()) { + continue; + } + + if (itemsOnly && searchType.hasBlockType()) { + continue; + } + final String id = searchType.getId(); + if (id.contains(idMatch)) { + Component name = searchType.getRichName(); + results.put(id, TextComponent.builder() + .append(name) + .append(" (" + id + ")") + .build()); + } + } + List list = new ArrayList<>(results.values()); + return PaginationBox.fromComponents("Search results for '" + search + "'", command, list) + .create(page); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java new file mode 100644 index 0000000..94aaf63 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -0,0 +1,407 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.Radii; +import com.sk89q.worldedit.internal.annotation.Selection; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.TreeGenerator.TreeType; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.biome.BiomeType; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.command.util.Logging.LogMode.*; +import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument; + +/** + * Commands for the generation of shapes and other objects. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class GenerationCommands { + + private final WorldEdit worldEdit; + + /** + * Create a new instance. + * + * @param worldEdit reference to WorldEdit + */ + public GenerationCommands(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + + @Command( + name = "/hcyl", + desc = "Generates a hollow cylinder." + ) + @CommandPermissions("worldedit.generation.cylinder") + @Logging(PLACEMENT) + public int hcyl(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to generate") + Pattern pattern, + @Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W") + @Radii(2) + List radii, + @Arg(desc = "The height of the cylinder", def = "1") + int height) throws WorldEditException { + return cyl(actor, session, editSession, pattern, radii, height, true); + } + + @Command( + name = "/cyl", + desc = "Generates a cylinder." + ) + @CommandPermissions("worldedit.generation.cylinder") + @Logging(PLACEMENT) + public int cyl(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to generate") + Pattern pattern, + @Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W") + @Radii(2) + List radii, + @Arg(desc = "The height of the cylinder", def = "1") + int height, + @Switch(name = 'h', desc = "Make a hollow cylinder") + boolean hollow) throws WorldEditException { + double radiusX; + double radiusZ; + switch (radii.size()) { + case 1: + radiusX = radiusZ = Math.max(1, radii.get(0)); + break; + + case 2: + radiusX = Math.max(1, radii.get(0)); + radiusZ = Math.max(1, radii.get(1)); + break; + + default: + actor.printError(TranslatableComponent.of("worldedit.cyl.invalid-radius")); + return 0; + } + + worldEdit.checkMaxRadius(radiusX); + worldEdit.checkMaxRadius(radiusZ); + worldEdit.checkMaxRadius(height); + + BlockVector3 pos = session.getPlacementPosition(actor); + int affected = editSession.makeCylinder(pos, pattern, radiusX, radiusZ, height, !hollow); + actor.printInfo(TranslatableComponent.of("worldedit.cyl.created", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/hsphere", + desc = "Generates a hollow sphere." + ) + @CommandPermissions("worldedit.generation.sphere") + @Logging(PLACEMENT) + public int hsphere(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to generate") + Pattern pattern, + @Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W") + @Radii(3) + List radii, + @Switch(name = 'r', desc = "Raise the bottom of the sphere to the placement position") + boolean raised) throws WorldEditException { + return sphere(actor, session, editSession, pattern, radii, raised, true); + } + + @Command( + name = "/sphere", + desc = "Generates a filled sphere." + ) + @CommandPermissions("worldedit.generation.sphere") + @Logging(PLACEMENT) + public int sphere(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to generate") + Pattern pattern, + @Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W") + @Radii(3) + List radii, + @Switch(name = 'r', desc = "Raise the bottom of the sphere to the placement position") + boolean raised, + @Switch(name = 'h', desc = "Make a hollow sphere") + boolean hollow) throws WorldEditException { + double radiusX; + double radiusY; + double radiusZ; + switch (radii.size()) { + case 1: + radiusX = radiusY = radiusZ = Math.max(0, radii.get(0)); + break; + + case 3: + radiusX = Math.max(0, radii.get(0)); + radiusY = Math.max(0, radii.get(1)); + radiusZ = Math.max(0, radii.get(2)); + break; + + default: + actor.printError(TranslatableComponent.of("worldedit.sphere.invalid-radius")); + return 0; + } + + worldEdit.checkMaxRadius(radiusX); + worldEdit.checkMaxRadius(radiusY); + worldEdit.checkMaxRadius(radiusZ); + + BlockVector3 pos = session.getPlacementPosition(actor); + if (raised) { + pos = pos.add(0, (int) radiusY, 0); + } + + int affected = editSession.makeSphere(pos, pattern, radiusX, radiusY, radiusZ, !hollow); + if (actor instanceof Player) { + ((Player) actor).findFreePosition(); + } + actor.printInfo(TranslatableComponent.of("worldedit.sphere.created", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "forestgen", + desc = "Generate a forest" + ) + @CommandPermissions("worldedit.generation.forest") + @Logging(POSITION) + public int forestGen(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The size of the forest, in blocks", def = "10") + int size, + @Arg(desc = "The type of forest", def = "tree") + TreeType type, + @Arg(desc = "The density of the forest, between 0 and 100", def = "5") + double density) throws WorldEditException { + checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); + worldEdit.checkMaxRadius(size); + density /= 100; + int affected = editSession.makeForest(session.getPlacementPosition(actor), size, density, type); + actor.printInfo(TranslatableComponent.of("worldedit.forestgen.created", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "pumpkins", + desc = "Generate pumpkin patches" + ) + @CommandPermissions("worldedit.generation.pumpkins") + @Logging(POSITION) + public int pumpkins(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The size of the patch", def = "10") + int size) throws WorldEditException { + worldEdit.checkMaxRadius(size); + int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), size); + actor.printInfo(TranslatableComponent.of("worldedit.pumpkins.created", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/hpyramid", + desc = "Generate a hollow pyramid" + ) + @CommandPermissions("worldedit.generation.pyramid") + @Logging(PLACEMENT) + public int hollowPyramid(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern, + @Arg(desc = "The size of the pyramid") + int size) throws WorldEditException { + return pyramid(actor, session, editSession, pattern, size, true); + } + + @Command( + name = "/pyramid", + desc = "Generate a filled pyramid" + ) + @CommandPermissions("worldedit.generation.pyramid") + @Logging(PLACEMENT) + public int pyramid(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern, + @Arg(desc = "The size of the pyramid") + int size, + @Switch(name = 'h', desc = "Make a hollow pyramid") + boolean hollow) throws WorldEditException { + worldEdit.checkMaxRadius(size); + BlockVector3 pos = session.getPlacementPosition(actor); + int affected = editSession.makePyramid(pos, pattern, size, !hollow); + if (actor instanceof Player) { + ((Player) actor).findFreePosition(); + } + actor.printInfo(TranslatableComponent.of("worldedit.pyramid.created", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/generate", + aliases = { "/gen", "/g" }, + desc = "Generates a shape according to a formula.", + descFooter = "For details, see https://ehub.to/we/expr" + ) + @CommandPermissions("worldedit.generation.shape") + @Logging(ALL) + public int generate(Actor actor, LocalSession session, EditSession editSession, + @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern, + @Arg(desc = "Expression to test block placement locations and set block type", variable = true) + List expression, + @Switch(name = 'h', desc = "Generate a hollow shape") + boolean hollow, + @Switch(name = 'r', desc = "Use the game's coordinate origin") + boolean useRawCoords, + @Switch(name = 'o', desc = "Use the placement's coordinate origin") + boolean offset, + @Switch(name = 'c', desc = "Use the selection's center as origin") + boolean offsetCenter) throws WorldEditException { + + final Vector3 zero; + Vector3 unit; + + if (useRawCoords) { + zero = Vector3.ZERO; + unit = Vector3.ONE; + } else if (offset) { + zero = session.getPlacementPosition(actor).toVector3(); + unit = Vector3.ONE; + } else if (offsetCenter) { + final Vector3 min = region.getMinimumPoint().toVector3(); + final Vector3 max = region.getMaximumPoint().toVector3(); + + zero = max.add(min).multiply(0.5); + unit = Vector3.ONE; + } else { + final Vector3 min = region.getMinimumPoint().toVector3(); + final Vector3 max = region.getMaximumPoint().toVector3(); + + zero = max.add(min).multiply(0.5); + unit = max.subtract(zero); + + if (unit.getX() == 0) { + unit = unit.withX(1.0); + } + if (unit.getY() == 0) { + unit = unit.withY(1.0); + } + if (unit.getZ() == 0) { + unit = unit.withZ(1.0); + } + } + + try { + final int affected = editSession.makeShape(region, zero, unit, pattern, String.join(" ", expression), hollow, session.getTimeout()); + if (actor instanceof Player) { + ((Player) actor).findFreePosition(); + } + actor.printInfo(TranslatableComponent.of("worldedit.generate.created", TextComponent.of(affected))); + return affected; + } catch (ExpressionException e) { + actor.printError(TextComponent.of(e.getMessage())); + return 0; + } + } + + @Command( + name = "/generatebiome", + aliases = { "/genbiome", "/gb" }, + desc = "Sets biome according to a formula.", + descFooter = "For details, see https://ehub.to/we/expr" + ) + @CommandPermissions("worldedit.generation.shape.biome") + @Logging(ALL) + public int generateBiome(Actor actor, LocalSession session, EditSession editSession, + @Selection Region region, + @Arg(desc = "The biome type to set") + BiomeType target, + @Arg(desc = "Expression to test block placement locations and set biome type", variable = true) + List expression, + @Switch(name = 'h', desc = "Generate a hollow shape") + boolean hollow, + @Switch(name = 'r', desc = "Use the game's coordinate origin") + boolean useRawCoords, + @Switch(name = 'o', desc = "Use the placement's coordinate origin") + boolean offset, + @Switch(name = 'c', desc = "Use the selection's center as origin") + boolean offsetCenter) throws WorldEditException { + final Vector3 zero; + Vector3 unit; + + if (useRawCoords) { + zero = Vector3.ZERO; + unit = Vector3.ONE; + } else if (offset) { + zero = session.getPlacementPosition(actor).toVector3(); + unit = Vector3.ONE; + } else if (offsetCenter) { + final Vector3 min = region.getMinimumPoint().toVector3(); + final Vector3 max = region.getMaximumPoint().toVector3(); + + zero = max.add(min).multiply(0.5); + unit = Vector3.ONE; + } else { + final Vector3 min = region.getMinimumPoint().toVector3(); + final Vector3 max = region.getMaximumPoint().toVector3(); + + zero = max.add(min).multiply(0.5); + unit = max.subtract(zero); + + if (unit.getX() == 0) { + unit = unit.withX(1.0); + } + if (unit.getY() == 0) { + unit = unit.withY(1.0); + } + if (unit.getZ() == 0) { + unit = unit.withZ(1.0); + } + } + + try { + final int affected = editSession.makeBiomeShape(region, zero, unit, target, String.join(" ", expression), hollow, session.getTimeout()); + actor.printInfo(TranslatableComponent.of("worldedit.generatebiome.changed", TextComponent.of(affected))); + return affected; + } catch (ExpressionException e) { + actor.printError(TextComponent.of(e.getMessage())); + return 0; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java new file mode 100644 index 0000000..19a0f7e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -0,0 +1,146 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Commands to undo, redo, and clear history. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class HistoryCommands { + + private final WorldEdit worldEdit; + + /** + * Create a new instance. + * + * @param worldEdit reference to WorldEdit + */ + public HistoryCommands(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + + @Command( + name = "undo", + aliases = { "/undo" }, + desc = "Undoes the last action (from history)" + ) + @CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"}) + public void undo(Actor actor, LocalSession session, + @Arg(desc = "Number of undoes to perform", def = "1") + int times, + @Arg(name = "player", desc = "Undo this player's operations", def = "") + String playerName) throws WorldEditException { + times = Math.max(1, times); + LocalSession undoSession = session; + if (playerName != null) { + actor.checkPermission("worldedit.history.undo.other"); + undoSession = worldEdit.getSessionManager().findByName(playerName); + if (undoSession == null) { + actor.printError(TranslatableComponent.of("worldedit.session.cant-find-session", TextComponent.of(playerName))); + return; + } + } + int timesUndone = 0; + for (int i = 0; i < times; ++i) { + BlockBag blockBag = actor instanceof Player ? undoSession.getBlockBag((Player) actor) : null; + EditSession undone = undoSession.undo(blockBag, actor); + if (undone != null) { + timesUndone++; + worldEdit.flushBlockBag(actor, undone); + } else { + break; + } + } + if (timesUndone > 0) { + actor.printInfo(TranslatableComponent.of("worldedit.undo.undone", TextComponent.of(timesUndone))); + } else { + actor.printError(TranslatableComponent.of("worldedit.undo.none")); + } + } + + @Command( + name = "redo", + aliases = { "/redo" }, + desc = "Redoes the last action (from history)" + ) + @CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"}) + public void redo(Actor actor, LocalSession session, + @Arg(desc = "Number of redoes to perform", def = "1") + int times, + @Arg(name = "player", desc = "Redo this player's operations", def = "") + String playerName) throws WorldEditException { + times = Math.max(1, times); + LocalSession redoSession = session; + if (playerName != null) { + actor.checkPermission("worldedit.history.redo.other"); + redoSession = worldEdit.getSessionManager().findByName(playerName); + if (redoSession == null) { + actor.printError(TranslatableComponent.of("worldedit.session.cant-find-session", TextComponent.of(playerName))); + return; + } + } + int timesRedone = 0; + for (int i = 0; i < times; ++i) { + BlockBag blockBag = actor instanceof Player ? redoSession.getBlockBag((Player) actor) : null; + EditSession redone = redoSession.redo(blockBag, actor); + if (redone != null) { + timesRedone++; + worldEdit.flushBlockBag(actor, redone); + } else { + break; + } + } + if (timesRedone > 0) { + actor.printInfo(TranslatableComponent.of("worldedit.redo.redone", TextComponent.of(timesRedone))); + } else { + actor.printError(TranslatableComponent.of("worldedit.redo.none")); + } + } + + @Command( + name = "clearhistory", + aliases = { "/clearhistory" }, + desc = "Clear your history" + ) + @CommandPermissions("worldedit.history.clear") + public void clearHistory(Actor actor, LocalSession session) { + session.clearHistory(); + actor.printInfo(TranslatableComponent.of("worldedit.clearhistory.cleared")); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/InsufficientArgumentsException.java b/src/main/java/com/sk89q/worldedit/command/InsufficientArgumentsException.java new file mode 100644 index 0000000..54f346d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/InsufficientArgumentsException.java @@ -0,0 +1,36 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.Component; + +public class InsufficientArgumentsException extends WorldEditException { + + @Deprecated + public InsufficientArgumentsException(String error) { + super(error); + } + + public InsufficientArgumentsException(Component error) { + super(error); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/LegacySnapshotCommands.java b/src/main/java/com/sk89q/worldedit/command/LegacySnapshotCommands.java new file mode 100644 index 0000000..eb56ce7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/LegacySnapshotCommands.java @@ -0,0 +1,203 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException; +import com.sk89q.worldedit.world.snapshot.Snapshot; +import com.sk89q.worldedit.world.storage.MissingWorldException; + +import java.io.File; +import java.io.IOException; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +/** + * Legacy snapshot command implementations. Commands are still registered via + * {@link SnapshotCommands}, but it delegates to this class when legacy snapshots are in use. + */ +class LegacySnapshotCommands { + + private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z"); + + private final WorldEdit we; + + LegacySnapshotCommands(WorldEdit we) { + this.we = we; + } + + void list(Actor actor, World world, int page) throws WorldEditException { + LocalConfiguration config = we.getConfiguration(); + + try { + List snapshots = config.snapshotRepo.getSnapshots(true, world.getName()); + + if (!snapshots.isEmpty()) { + actor.print(new SnapshotListBox(world.getName(), snapshots).create(page)); + } else { + actor.printError(TranslatableComponent.of("worldedit.restore.none-found-console")); + + // Okay, let's toss some debugging information! + File dir = config.snapshotRepo.getDirectory(); + + try { + WorldEdit.logger.info("WorldEdit found no snapshots: looked in: " + + dir.getCanonicalPath()); + } catch (IOException e) { + WorldEdit.logger.info("WorldEdit found no snapshots: looked in " + + "(NON-RESOLVABLE PATH - does it exist?): " + + dir.getPath()); + } + } + } catch (MissingWorldException ex) { + actor.printError(TranslatableComponent.of("worldedit.restore.none-for-world")); + } + } + + void use(Actor actor, World world, LocalSession session, String name) { + LocalConfiguration config = we.getConfiguration(); + + // Want the latest snapshot? + if (name.equalsIgnoreCase("latest")) { + try { + Snapshot snapshot = config.snapshotRepo.getDefaultSnapshot(world.getName()); + + if (snapshot != null) { + session.setSnapshot(null); + actor.printInfo(TranslatableComponent.of("worldedit.snapshot.use.newest")); + } else { + actor.printError(TranslatableComponent.of("worldedit.restore.none-found")); + } + } catch (MissingWorldException ex) { + actor.printError(TranslatableComponent.of("worldedit.restore.none-for-world")); + } + } else { + try { + session.setSnapshot(config.snapshotRepo.getSnapshot(name)); + actor.printInfo(TranslatableComponent.of("worldedit.snapshot.use", TextComponent.of(name))); + } catch (InvalidSnapshotException e) { + actor.printError(TranslatableComponent.of("worldedit.restore.not-available")); + } + } + } + + void sel(Actor actor, World world, LocalSession session, int index) { + LocalConfiguration config = we.getConfiguration(); + + if (index < 1) { + actor.printError(TranslatableComponent.of("worldedit.snapshot.index-above-0")); + return; + } + + try { + List snapshots = config.snapshotRepo.getSnapshots(true, world.getName()); + if (snapshots.size() < index) { + actor.printError(TranslatableComponent.of("worldedit.snapshot.index-oob", TextComponent.of(snapshots.size()))); + return; + } + Snapshot snapshot = snapshots.get(index - 1); + if (snapshot == null) { + actor.printError(TranslatableComponent.of("worldedit.restore.not-available")); + return; + } + session.setSnapshot(snapshot); + actor.printInfo(TranslatableComponent.of("worldedit.snapshot.use", TextComponent.of(snapshot.getName()))); + } catch (MissingWorldException e) { + actor.printError(TranslatableComponent.of("worldedit.restore.none-for-world")); + } + } + + void before(Actor actor, World world, LocalSession session, ZonedDateTime date) { + LocalConfiguration config = we.getConfiguration(); + + try { + Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, world.getName()); + + if (snapshot == null) { + actor.printError(TranslatableComponent.of( + "worldedit.snapshot.none-before", + TextComponent.of(dateFormat.withZone(session.getTimeZone()).format(date))) + ); + } else { + session.setSnapshot(snapshot); + actor.printInfo(TranslatableComponent.of("worldedit.snapshot.use", TextComponent.of(snapshot.getName()))); + } + } catch (MissingWorldException ex) { + actor.printError(TranslatableComponent.of("worldedit.restore.none-for-world")); + } + } + + void after(Actor actor, World world, LocalSession session, ZonedDateTime date) { + LocalConfiguration config = we.getConfiguration(); + + try { + Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, world.getName()); + if (snapshot == null) { + actor.printError(TranslatableComponent.of( + "worldedit.snapshot.none-after", + TextComponent.of(dateFormat.withZone(session.getTimeZone()).format(date))) + ); + } else { + session.setSnapshot(snapshot); + actor.printInfo(TranslatableComponent.of("worldedit.snapshot.use", TextComponent.of(snapshot.getName()))); + } + } catch (MissingWorldException ex) { + actor.printError(TranslatableComponent.of("worldedit.restore.none-for-world")); + } + } + + private static class SnapshotListBox extends PaginationBox { + private final List snapshots; + + SnapshotListBox(String world, List snapshots) { + super("Snapshots for: " + world, "/snap list -p %page%"); + this.snapshots = snapshots; + } + + @Override + public Component getComponent(int number) { + final Snapshot snapshot = snapshots.get(number); + return TextComponent.of(number + 1 + ". ", TextColor.GOLD) + .append(TextComponent.of(snapshot.getName(), TextColor.LIGHT_PURPLE) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to use"))) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/snap use " + snapshot.getName()))); + } + + @Override + public int getComponentsSize() { + return snapshots.size(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/LegacySnapshotUtilCommands.java b/src/main/java/com/sk89q/worldedit/command/LegacySnapshotUtilCommands.java new file mode 100644 index 0000000..a42f634 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/LegacySnapshotUtilCommands.java @@ -0,0 +1,132 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.regions.Region; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException; +import com.sk89q.worldedit.world.snapshot.Snapshot; +import com.sk89q.worldedit.world.snapshot.SnapshotRestore; +import com.sk89q.worldedit.world.storage.ChunkStore; +import com.sk89q.worldedit.world.storage.MissingWorldException; + +import java.io.File; +import java.io.IOException; + +class LegacySnapshotUtilCommands { + + private final WorldEdit we; + + LegacySnapshotUtilCommands(WorldEdit we) { + this.we = we; + } + + void restore(Actor actor, World world, LocalSession session, EditSession editSession, + String snapshotName) throws WorldEditException { + LocalConfiguration config = we.getConfiguration(); + + Region region = session.getSelection(world); + Snapshot snapshot; + + if (snapshotName != null) { + try { + snapshot = config.snapshotRepo.getSnapshot(snapshotName); + } catch (InvalidSnapshotException e) { + actor.printError(TranslatableComponent.of("worldedit.restore.not-available")); + return; + } + } else { + snapshot = session.getSnapshot(); + } + + // No snapshot set? + if (snapshot == null) { + try { + snapshot = config.snapshotRepo.getDefaultSnapshot(world.getName()); + + if (snapshot == null) { + actor.printError(TranslatableComponent.of("worldedit.restore.none-found-console")); + + // Okay, let's toss some debugging information! + File dir = config.snapshotRepo.getDirectory(); + + try { + WorldEdit.logger.info("WorldEdit found no snapshots: looked in: " + + dir.getCanonicalPath()); + } catch (IOException e) { + WorldEdit.logger.info("WorldEdit found no snapshots: looked in " + + "(NON-RESOLVABLE PATH - does it exist?): " + + dir.getPath()); + } + + return; + } + } catch (MissingWorldException ex) { + actor.printError(TranslatableComponent.of("worldedit.restore.none-for-world")); + return; + } + } + + ChunkStore chunkStore; + + // Load chunk store + try { + chunkStore = snapshot.getChunkStore(); + actor.printInfo(TranslatableComponent.of("worldedit.restore.loaded", TextComponent.of(snapshot.getName()))); + } catch (DataException | IOException e) { + actor.printError(TranslatableComponent.of("worldedit.restore.failed", TextComponent.of(e.getMessage()))); + return; + } + + try { + // Restore snapshot + SnapshotRestore restore = new SnapshotRestore(chunkStore, editSession, region); + //player.print(restore.getChunksAffected() + " chunk(s) will be loaded."); + + restore.restore(); + + if (restore.hadTotalFailure()) { + String error = restore.getLastErrorMessage(); + if (!restore.getMissingChunks().isEmpty()) { + actor.printError(TranslatableComponent.of("worldedit.restore.chunk-not-present")); + } else if (error != null) { + actor.printError(TranslatableComponent.of("worldedit.restore.block-place-failed")); + actor.printError(TranslatableComponent.of("worldedit.restore.block-place-error", TextComponent.of(error))); + } else { + actor.printError(TranslatableComponent.of("worldedit.restore.chunk-load-failed")); + } + } else { + actor.printInfo(TranslatableComponent.of("worldedit.restore.restored", + TextComponent.of(restore.getMissingChunks().size()), + TextComponent.of(restore.getErrorChunks().size()))); + } + } finally { + try { + chunkStore.close(); + } catch (IOException ignored) { + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java b/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java new file mode 100644 index 0000000..b29b47a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java @@ -0,0 +1,201 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; + +/** + * Commands for moving the player around. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class NavigationCommands { + + private final WorldEdit worldEdit; + + /** + * Create a new instance. + * + * @param worldEdit reference to WorldEdit + */ + public NavigationCommands(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + + @Command( + name = "unstuck", + aliases = { "!" }, + desc = "Escape from being stuck inside a block" + ) + @CommandPermissions("worldedit.navigation.unstuck") + public void unstuck(Player player) throws WorldEditException { + player.findFreePosition(); + player.printInfo(TranslatableComponent.of("worldedit.unstuck.moved")); + } + + @Command( + name = "ascend", + aliases = { "asc" }, + desc = "Go up a floor" + ) + @CommandPermissions("worldedit.navigation.ascend") + public void ascend(Player player, + @Arg(desc = "# of levels to ascend", def = "1") + int levels) throws WorldEditException { + int ascentLevels = 0; + while (player.ascendLevel()) { + ++ascentLevels; + if (levels == ascentLevels) { + break; + } + } + if (ascentLevels == 0) { + player.printError(TranslatableComponent.of("worldedit.ascend.obstructed")); + } else { + player.printInfo(TranslatableComponent.of("worldedit.ascend.moved", TextComponent.of(ascentLevels))); + } + } + + @Command( + name = "descend", + aliases = { "desc" }, + desc = "Go down a floor" + ) + @CommandPermissions("worldedit.navigation.descend") + public void descend(Player player, + @Arg(desc = "# of levels to descend", def = "1") + int levels) throws WorldEditException { + int descentLevels = 0; + while (player.descendLevel()) { + ++descentLevels; + if (levels == descentLevels) { + break; + } + } + if (descentLevels == 0) { + player.printError(TranslatableComponent.of("worldedit.descend.obstructed")); + } else { + player.printInfo(TranslatableComponent.of("worldedit.descend.moved", TextComponent.of(descentLevels))); + } + } + + @Command( + name = "ceil", + desc = "Go to the ceiling" + ) + @CommandPermissions("worldedit.navigation.ceiling") + @Logging(POSITION) + public void ceiling(Player player, + @Arg(desc = "# of blocks to leave above you", def = "0") + int clearance, + @Switch(name = 'f', desc = "Force using flight to keep you still") + boolean forceFlight, + @Switch(name = 'g', desc = "Force using glass to keep you still") + boolean forceGlass) throws WorldEditException { + clearance = Math.max(0, clearance); + + boolean alwaysGlass = getAlwaysGlass(forceFlight, forceGlass); + if (player.ascendToCeiling(clearance, alwaysGlass)) { + player.printInfo(TranslatableComponent.of("worldedit.ceil.moved")); + } else { + player.printError(TranslatableComponent.of("worldedit.ceil.obstructed")); + } + } + + @Command( + name = "thru", + desc = "Pass through walls" + ) + @CommandPermissions("worldedit.navigation.thru.command") + public void thru(Player player) throws WorldEditException { + if (player.passThroughForwardWall(6)) { + player.printInfo(TranslatableComponent.of("worldedit.thru.moved")); + } else { + player.printError(TranslatableComponent.of("worldedit.thru.obstructed")); + } + } + + @Command( + name = "jumpto", + aliases = { "j" }, + desc = "Teleport to a location" + ) + @CommandPermissions("worldedit.navigation.jumpto.command") + public void jumpTo(Player player) throws WorldEditException { + + Location pos = player.getSolidBlockTrace(300); + if (pos != null) { + player.findFreePosition(pos); + player.printInfo(TranslatableComponent.of("worldedit.jumpto.moved")); + } else { + player.printError(TranslatableComponent.of("worldedit.jumpto.none")); + } + } + + @Command( + name = "up", + desc = "Go upwards some distance" + ) + @CommandPermissions("worldedit.navigation.up") + @Logging(POSITION) + public void up(Player player, + @Arg(desc = "Distance to go upwards") + int distance, + @Switch(name = 'f', desc = "Force using flight to keep you still") + boolean forceFlight, + @Switch(name = 'g', desc = "Force using glass to keep you still") + boolean forceGlass) throws WorldEditException { + boolean alwaysGlass = getAlwaysGlass(forceFlight, forceGlass); + if (player.ascendUpwards(distance, alwaysGlass)) { + player.printInfo(TranslatableComponent.of("worldedit.up.moved")); + } else { + player.printError(TranslatableComponent.of("worldedit.up.obstructed")); + } + } + + /** + * Helper function for /up and /ceil. + * + * @param forceFlight if flight should be used, rather than the default config option + * @param forceGlass if glass should always be placed, rather than the default config option + * @return true, if glass should always be put under the player + */ + private boolean getAlwaysGlass(boolean forceFlight, boolean forceGlass) { + final LocalConfiguration config = worldEdit.getConfiguration(); + + return forceGlass || (config.navigationUseGlass && !forceFlight); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java b/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java new file mode 100644 index 0000000..4c2fec3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java @@ -0,0 +1,149 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.command.factory.ItemUseFactory; +import com.sk89q.worldedit.command.factory.ReplaceFactory; +import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.factory.Paint; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.regions.factory.RegionFactory; +import com.sk89q.worldedit.util.TreeGenerator; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; +import net.kyori.text.format.TextDecoration; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandManagerService; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.part.CommandArgument; +import org.enginehub.piston.part.SubCommandPart; + +import java.util.stream.Collectors; + +import static java.util.Objects.requireNonNull; +import static org.enginehub.piston.part.CommandParts.arg; + +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class PaintBrushCommands { + + private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("shape"), TranslatableComponent.of("worldedit.brush.paint.shape")) + .defaultsTo(ImmutableList.of()) + .ofTypes(ImmutableList.of(Key.of(RegionFactory.class))) + .build(); + + private static final CommandArgument RADIUS = arg(TranslatableComponent.of("radius"), TranslatableComponent.of("worldedit.brush.paint.size")) + .defaultsTo(ImmutableList.of("5")) + .ofTypes(ImmutableList.of(Key.of(double.class))) + .build(); + + private static final CommandArgument DENSITY = arg(TranslatableComponent.of("density"), TranslatableComponent.of("worldedit.brush.paint.density")) + .defaultsTo(ImmutableList.of("20")) + .ofTypes(ImmutableList.of(Key.of(double.class))) + .build(); + + public static void register(CommandManagerService service, CommandManager commandManager, CommandRegistrationHandler registration) { + commandManager.register("paint", builder -> { + builder.description(TranslatableComponent.of("worldedit.brush.paint.description")); + builder.action(org.enginehub.piston.Command.Action.NULL_ACTION); + + CommandManager manager = service.newCommandManager(); + registration.register( + manager, + PaintBrushCommandsRegistration.builder(), + new PaintBrushCommands() + ); + + builder.condition(new PermissionCondition(ImmutableSet.of("worldedit.brush.paint"))); + + builder.addParts(REGION_FACTORY, RADIUS, DENSITY); + builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TranslatableComponent.of("worldedit.brush.paint.type")) + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() + .build()); + }); + } + + private void setPaintBrush(CommandParameters parameters, Player player, LocalSession localSession, + Contextual generatorFactory) throws WorldEditException { + double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class)); + double density = requireNonNull(DENSITY.value(parameters).asSingle(double.class)) / 100; + RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class); + BrushCommands.setOperationBasedBrush(player, localSession, radius, + new Paint(generatorFactory, density), regionFactory, "worldedit.brush.paint"); + } + + @Command( + name = "forest", + desc = "Plant trees" + ) + public void forest(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The type of tree to plant") + TreeGenerator.TreeType type) throws WorldEditException { + setPaintBrush(parameters, player, localSession, new TreeGeneratorFactory(type)); + } + + @Command( + name = "item", + desc = "Use an item" + ) + @CommandPermissions("worldedit.brush.item") + public void item(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The type of item to use") + BaseItem item, + @Arg(desc = "The direction in which the item will be applied", def = "up") + @Direction(includeDiagonals = true) + com.sk89q.worldedit.util.Direction direction) throws WorldEditException { + player.print(TextComponent.builder().append("WARNING: ", TextColor.RED, TextDecoration.BOLD) + .append(TranslatableComponent.of("worldedit.brush.paint.item.warning")).build()); + setPaintBrush(parameters, player, localSession, new ItemUseFactory(item, direction)); + } + + @Command( + name = "set", + desc = "Place a block" + ) + public void set(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The pattern of blocks to use") + Pattern pattern) throws WorldEditException { + setPaintBrush(parameters, player, localSession, new ReplaceFactory(pattern)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/src/main/java/com/sk89q/worldedit/command/RegionCommands.java new file mode 100644 index 0000000..edb086b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -0,0 +1,566 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.GroundFunction; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.block.BlockReplace; +import com.sk89q.worldedit.function.generator.FloraGenerator; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.MaskIntersection; +import com.sk89q.worldedit.function.mask.NoiseFilter2D; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.visitor.LayerVisitor; +import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.internal.annotation.Offset; +import com.sk89q.worldedit.internal.annotation.Selection; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.convolution.GaussianKernel; +import com.sk89q.worldedit.math.convolution.HeightMap; +import com.sk89q.worldedit.math.convolution.HeightMapFilter; +import com.sk89q.worldedit.math.noise.RandomNoise; +import com.sk89q.worldedit.regions.ConvexPolyhedralRegion; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.util.TreeGenerator.TreeType; +import com.sk89q.worldedit.util.formatting.component.TextUtils; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.World; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; + +import java.util.ArrayList; +import java.util.List; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.*; +import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument; +import static com.sk89q.worldedit.regions.Regions.*; + +/** + * Commands that operate on regions. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class RegionCommands { + + /** + * Create a new instance. + */ + public RegionCommands() { + } + + @Command( + name = "/set", + desc = "Sets all the blocks in the region" + ) + @CommandPermissions("worldedit.region.set") + @Logging(REGION) + public int set(Actor actor, EditSession editSession, + @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern) { + RegionFunction set = new BlockReplace(editSession, pattern); + RegionVisitor visitor = new RegionVisitor(region, set); + + Operations.completeBlindly(visitor); + List messages = Lists.newArrayList(visitor.getStatusMessages()); + if (messages.isEmpty()) { + actor.printInfo(TranslatableComponent.of("worldedit.set.done")); + } else { + actor.printInfo(TranslatableComponent.of("worldedit.set.done.verbose", TextUtils.join(messages, TextComponent.of(", ")))); + } + + return visitor.getAffected(); + } + + @Command( + name = "/line", + desc = "Draws line segments between cuboid selection corners or convex polyhedral selection vertices", + descFooter = "Can only be used with a cuboid selection or a convex polyhedral selection" + ) + @CommandPermissions("worldedit.region.line") + @Logging(REGION) + public int line(Actor actor, EditSession editSession, + @Selection Region region, + @Arg(desc = "The pattern of blocks to place") + Pattern pattern, + @Arg(desc = "The thickness of the line", def = "0") + int thickness, + @Switch(name = 'h', desc = "Generate only a shell") + boolean shell) throws WorldEditException { + if (!((region instanceof CuboidRegion) || (region instanceof ConvexPolyhedralRegion))) { + actor.printError(TranslatableComponent.of("worldedit.line.invalid-type")); + return 0; + } + checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); + WorldEdit.getInstance().checkMaxRadius(thickness); + + List vectors; + + if (region instanceof CuboidRegion) { + CuboidRegion cuboidRegion = (CuboidRegion) region; + vectors = ImmutableList.of(cuboidRegion.getPos1(), cuboidRegion.getPos2()); + } else { + ConvexPolyhedralRegion convexRegion = (ConvexPolyhedralRegion) region; + vectors = ImmutableList.copyOf(convexRegion.getVertices()); + } + + int blocksChanged = editSession.drawLine(pattern, vectors, thickness, !shell); + + actor.printInfo(TranslatableComponent.of("worldedit.line.changed", TextComponent.of(blocksChanged))); + return blocksChanged; + } + + @Command( + name = "/curve", + desc = "Draws a spline through selected points", + descFooter = "Can only be used with a convex polyhedral selection" + ) + @CommandPermissions("worldedit.region.curve") + @Logging(REGION) + public int curve(Actor actor, EditSession editSession, + @Selection Region region, + @Arg(desc = "The pattern of blocks to place") + Pattern pattern, + @Arg(desc = "The thickness of the curve", def = "0") + int thickness, + @Switch(name = 'h', desc = "Generate only a shell") + boolean shell) throws WorldEditException { + if (!(region instanceof ConvexPolyhedralRegion)) { + actor.printError(TranslatableComponent.of("worldedit.curve.invalid-type")); + return 0; + } + checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); + WorldEdit.getInstance().checkMaxRadius(thickness); + + ConvexPolyhedralRegion cpregion = (ConvexPolyhedralRegion) region; + List vectors = new ArrayList<>(cpregion.getVertices()); + + int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell); + + actor.printInfo(TranslatableComponent.of("worldedit.curve.changed", TextComponent.of(blocksChanged))); + return blocksChanged; + } + + @Command( + name = "/replace", + aliases = { "/re", "/rep" }, + desc = "Replace all blocks in the selection with another" + ) + @CommandPermissions("worldedit.region.replace") + @Logging(REGION) + public int replace(Actor actor, EditSession editSession, @Selection Region region, + @Arg(desc = "The mask representing blocks to replace", def = "") + Mask from, + @Arg(desc = "The pattern of blocks to replace with") + Pattern to) throws WorldEditException { + if (from == null) { + from = new ExistingBlockMask(editSession); + } + int affected = editSession.replaceBlocks(region, from, to); + actor.printInfo(TranslatableComponent.of("worldedit.replace.replaced", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/overlay", + desc = "Set a block on top of blocks in the region" + ) + @CommandPermissions("worldedit.region.overlay") + @Logging(REGION) + public int overlay(Actor actor, EditSession editSession, @Selection Region region, + @Arg(desc = "The pattern of blocks to overlay") + Pattern pattern) throws WorldEditException { + int affected = editSession.overlayCuboidBlocks(region, pattern); + actor.printInfo(TranslatableComponent.of("worldedit.overlay.overlaid", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/center", + aliases = { "/middle" }, + desc = "Set the center block(s)" + ) + @Logging(REGION) + @CommandPermissions("worldedit.region.center") + public int center(Actor actor, EditSession editSession, @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern) throws WorldEditException { + int affected = editSession.center(region, pattern); + actor.printInfo(TranslatableComponent.of("worldedit.center.changed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/naturalize", + desc = "3 layers of dirt on top then rock below" + ) + @CommandPermissions("worldedit.region.naturalize") + @Logging(REGION) + public int naturalize(Actor actor, EditSession editSession, @Selection Region region) throws WorldEditException { + int affected = editSession.naturalizeCuboidBlocks(region); + actor.printInfo(TranslatableComponent.of("worldedit.naturalize.naturalized", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/walls", + desc = "Build the four sides of the selection" + ) + @CommandPermissions("worldedit.region.walls") + @Logging(REGION) + public int walls(Actor actor, EditSession editSession, @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern) throws WorldEditException { + int affected = editSession.makeWalls(region, pattern); + actor.printInfo(TranslatableComponent.of("worldedit.walls.changed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/faces", + aliases = { "/outline" }, + desc = "Build the walls, ceiling, and floor of a selection" + ) + @CommandPermissions("worldedit.region.faces") + @Logging(REGION) + public int faces(Actor actor, EditSession editSession, @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern) throws WorldEditException { + int affected = editSession.makeFaces(region, pattern); + actor.printInfo(TranslatableComponent.of("worldedit.faces.changed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/smooth", + desc = "Smooth the elevation in the selection", + descFooter = "Example: '//smooth 1 grass_block,dirt,stone' would only smooth natural surface terrain." + ) + @CommandPermissions("worldedit.region.smooth") + @Logging(REGION) + public int smooth(Actor actor, EditSession editSession, @Selection Region region, + @Arg(desc = "# of iterations to perform", def = "1") + int iterations, + @Arg(desc = "The mask of blocks to use as the height map", def = "") + Mask mask) throws WorldEditException { + HeightMap heightMap = new HeightMap(editSession, region, mask); + HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); + int affected = heightMap.applyFilter(filter, iterations); + actor.printInfo(TranslatableComponent.of("worldedit.smooth.changed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/move", + desc = "Move the contents of the selection" + ) + @CommandPermissions("worldedit.region.move") + @Logging(ORIENTATION_REGION) + public int move(Actor actor, World world, EditSession editSession, LocalSession session, + @Selection Region region, + @Arg(desc = "number of times to apply the offset", def = "1") + int multiplier, + @Arg(desc = "The offset to move", def = Offset.FORWARD) + @Offset + BlockVector3 offset, + @Arg(desc = "The pattern of blocks to leave", def = "air") + Pattern replace, + @Switch(name = 's', desc = "Shift the selection to the target location") + boolean moveSelection, + @Switch(name = 'a', desc = "Ignore air blocks") + boolean ignoreAirBlocks, + @Switch(name = 'e', desc = "Also copy entities") + boolean copyEntities, + @Switch(name = 'b', desc = "Also copy biomes") + boolean copyBiomes, + @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air") + Mask mask) throws WorldEditException { + checkCommandArgument(multiplier >= 1, "Multiplier must be >= 1"); + + Mask combinedMask; + if (ignoreAirBlocks) { + if (mask == null) { + combinedMask = new ExistingBlockMask(editSession); + } else { + combinedMask = new MaskIntersection(mask, new ExistingBlockMask(editSession)); + } + } else { + combinedMask = mask; + } + + int affected = editSession.moveRegion(region, offset, multiplier, copyEntities, copyBiomes, combinedMask, replace); + + if (moveSelection) { + try { + region.shift(offset.multiply(multiplier)); + + session.getRegionSelector(world).learnChanges(); + session.getRegionSelector(world).explainRegionAdjust(actor, session); + } catch (RegionOperationException e) { + actor.printError(e.getRichMessage()); + } + } + + actor.printInfo(TranslatableComponent.of("worldedit.move.moved", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/stack", + desc = "Repeat the contents of the selection" + ) + @CommandPermissions("worldedit.region.stack") + @Logging(ORIENTATION_REGION) + public int stack(Actor actor, World world, EditSession editSession, LocalSession session, + @Selection Region region, + @Arg(desc = "# of copies to stack", def = "1") + int count, + @Arg(desc = "How far to move the contents each stack", def = Offset.FORWARD) + @Offset + BlockVector3 offset, + @Switch(name = 's', desc = "Shift the selection to the last stacked copy") + boolean moveSelection, + @Switch(name = 'a', desc = "Ignore air blocks") + boolean ignoreAirBlocks, + @Switch(name = 'e', desc = "Also copy entities") + boolean copyEntities, + @Switch(name = 'b', desc = "Also copy biomes") + boolean copyBiomes, + @Switch(name = 'r', desc = "Use block units") + boolean blockUnits, + @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air") + Mask mask) throws WorldEditException { + checkCommandArgument(count >= 1, "Count must be >= 1"); + + Mask combinedMask; + if (ignoreAirBlocks) { + if (mask == null) { + combinedMask = new ExistingBlockMask(editSession); + } else { + combinedMask = new MaskIntersection(mask, new ExistingBlockMask(editSession)); + } + } else { + combinedMask = mask; + } + + int affected; + if (blockUnits) { + affected = editSession.stackRegionBlockUnits(region, offset, count, copyEntities, copyBiomes, combinedMask); + } else { + affected = editSession.stackCuboidRegion(region, offset, count, copyEntities, copyBiomes, combinedMask); + } + + if (moveSelection) { + try { + final BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); + + final BlockVector3 shiftSize = blockUnits ? offset : offset.multiply(size); + final BlockVector3 shiftVector = shiftSize.multiply(count); + region.shift(shiftVector); + + session.getRegionSelector(world).learnChanges(); + session.getRegionSelector(world).explainRegionAdjust(actor, session); + } catch (RegionOperationException e) { + actor.printError(e.getRichMessage()); + } + } + + actor.printInfo(TranslatableComponent.of("worldedit.stack.changed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/regen", + desc = "Regenerates the contents of the selection" + ) + @CommandPermissions("worldedit.regen") + @Logging(REGION) + void regenerate(Actor actor, World world, LocalSession session, EditSession editSession, + @Selection Region region, + @Arg(desc = "The seed to regenerate with, otherwise uses world seed", def = "") + Long seed, + @Switch(name = 'b', desc = "Regenerate biomes as well") + boolean regenBiomes) { + Mask mask = session.getMask(); + boolean success; + try { + session.setMask(null); + RegenOptions options = RegenOptions.builder() + .seed(seed) + .regenBiomes(regenBiomes) + .build(); + success = world.regenerate(region, editSession, options); + } finally { + session.setMask(mask); + } + if (success) { + actor.printInfo(TranslatableComponent.of("worldedit.regen.regenerated")); + } else { + actor.printError(TranslatableComponent.of("worldedit.regen.failed")); + } + } + + @Command( + name = "/deform", + desc = "Deforms a selected region with an expression", + descFooter = "The expression is executed for each block and is expected\n" + + "to modify the variables x, y and z to point to a new block\n" + + "to fetch. For details, see https://ehub.to/we/expr" + ) + @CommandPermissions("worldedit.region.deform") + @Logging(ALL) + public int deform(Actor actor, LocalSession session, EditSession editSession, + @Selection Region region, + @Arg(desc = "The expression to use", variable = true) + List expression, + @Switch(name = 'r', desc = "Use the game's coordinate origin") + boolean useRawCoords, + @Switch(name = 'o', desc = "Use the placement's coordinate origin") + boolean offset, + @Switch(name = 'c', desc = "Use the selection's center as origin") + boolean offsetCenter) throws WorldEditException { + final Vector3 zero; + Vector3 unit; + + if (useRawCoords) { + zero = Vector3.ZERO; + unit = Vector3.ONE; + } else if (offset) { + zero = session.getPlacementPosition(actor).toVector3(); + unit = Vector3.ONE; + } else if (offsetCenter) { + final Vector3 min = region.getMinimumPoint().toVector3(); + final Vector3 max = region.getMaximumPoint().toVector3(); + + zero = max.add(min).multiply(0.5); + unit = Vector3.ONE; + } else { + final Vector3 min = region.getMinimumPoint().toVector3(); + final Vector3 max = region.getMaximumPoint().toVector3(); + + zero = max.add(min).divide(2); + unit = max.subtract(zero); + + if (unit.getX() == 0) { + unit = unit.withX(1.0); + } + if (unit.getY() == 0) { + unit = unit.withY(1.0); + } + if (unit.getZ() == 0) { + unit = unit.withZ(1.0); + } + } + + try { + final int affected = editSession.deformRegion(region, zero, unit, String.join(" ", expression), session.getTimeout()); + if (actor instanceof Player) { + ((Player) actor).findFreePosition(); + } + actor.printInfo(TranslatableComponent.of("worldedit.deform.deformed", TextComponent.of(affected))); + return affected; + } catch (ExpressionException e) { + actor.printError(TextComponent.of(e.getMessage())); + return 0; + } + } + + @Command( + name = "/hollow", + desc = "Hollows out the object contained in this selection", + descFooter = "Thickness is measured in manhattan distance." + ) + @CommandPermissions("worldedit.region.hollow") + @Logging(REGION) + public int hollow(Actor actor, EditSession editSession, + @Selection Region region, + @Arg(desc = "Thickness of the shell to leave", def = "0") + int thickness, + @Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air") + Pattern pattern) throws WorldEditException { + checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); + + int affected = editSession.hollowOutRegion(region, thickness, pattern); + actor.printInfo(TranslatableComponent.of("worldedit.hollow.changed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/forest", + desc = "Make a forest within the region" + ) + @CommandPermissions("worldedit.region.forest") + @Logging(REGION) + public int forest(Actor actor, EditSession editSession, @Selection Region region, + @Arg(desc = "The type of tree to place", def = "tree") + TreeType type, + @Arg(desc = "The density of the forest", def = "5") + double density) throws WorldEditException { + checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); + int affected = editSession.makeForest(region, density / 100, type); + actor.printInfo(TranslatableComponent.of("worldedit.forest.created", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/flora", + desc = "Make flora within the region" + ) + @CommandPermissions("worldedit.region.flora") + @Logging(REGION) + public int flora(Actor actor, EditSession editSession, @Selection Region region, + @Arg(desc = "The density of the forest", def = "5") + double density) throws WorldEditException { + checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); + density = density / 100; + FloraGenerator generator = new FloraGenerator(editSession); + GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator); + LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + Operations.completeLegacy(visitor); + + int affected = ground.getAffected(); + actor.printInfo(TranslatableComponent.of("worldedit.flora.created", TextComponent.of(affected))); + return affected; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java new file mode 100644 index 0000000..715ff44 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -0,0 +1,464 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.common.collect.ImmutableList; +import com.google.common.io.MoreFiles; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.AsyncCommandBuilder; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.formatting.component.CodeFormat; +import com.sk89q.worldedit.util.formatting.component.ErrorFormat; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.component.SubtleFormat; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.io.Closer; +import com.sk89q.worldedit.util.io.file.FilenameException; +import com.sk89q.worldedit.util.io.file.MorePaths; +import org.apache.logging.log4j.Logger; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.StopExecutionException; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.Callable; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Commands that work with schematic files. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class SchematicCommands { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private final WorldEdit worldEdit; + + /** + * Create a new instance. + * + * @param worldEdit reference to WorldEdit + */ + public SchematicCommands(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + + @Command( + name = "load", + desc = "Load a schematic into your clipboard" + ) + @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load"}) + public void load(Actor actor, LocalSession session, + @Arg(desc = "File name.") + String filename, + @Arg(desc = "Format name.", def = "sponge") + String formatName) throws FilenameException { + LocalConfiguration config = worldEdit.getConfiguration(); + + File dir = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); + File f = worldEdit.getSafeOpenFile(actor, dir, filename, + BuiltInClipboardFormat.SPONGE_SCHEMATIC.getPrimaryFileExtension(), + ClipboardFormats.getFileExtensionArray()); + + if (!f.exists()) { + actor.printError(TranslatableComponent.of("worldedit.schematic.load.does-not-exist", TextComponent.of(filename))); + return; + } + + ClipboardFormat format = ClipboardFormats.findByFile(f); + if (format == null) { + format = ClipboardFormats.findByAlias(formatName); + } + if (format == null) { + actor.printError(TranslatableComponent.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); + return; + } + + SchematicLoadTask task = new SchematicLoadTask(actor, f, format); + AsyncCommandBuilder.wrap(task, actor) + .registerWithSupervisor(worldEdit.getSupervisor(), "Loading schematic " + filename) + .setDelayMessage(TranslatableComponent.of("worldedit.schematic.load.loading")) + .setWorkingMessage(TranslatableComponent.of("worldedit.schematic.load.still-loading")) + .onSuccess(TextComponent.of(filename, TextColor.GOLD) + .append(TextComponent.of(" loaded. Paste it with ", TextColor.LIGHT_PURPLE)) + .append(CodeFormat.wrap("//paste").clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "//paste"))), + session::setClipboard) + .onFailure("Failed to load schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter()) + .buildAndExec(worldEdit.getExecutorService()); + } + + @Command( + name = "save", + desc = "Save a schematic into your clipboard" + ) + @CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" }) + public void save(Actor actor, LocalSession session, + @Arg(desc = "File name.") + String filename, + @Arg(desc = "Format name.", def = "sponge") + String formatName, + @Switch(name = 'f', desc = "Overwrite an existing file.") + boolean allowOverwrite) throws WorldEditException { + if (worldEdit.getPlatformManager().queryCapability(Capability.GAME_HOOKS).getDataVersion() == -1) { + actor.printError(TranslatableComponent.of("worldedit.schematic.unsupported-minecraft-version")); + return; + } + + LocalConfiguration config = worldEdit.getConfiguration(); + + File dir = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); + + ClipboardFormat format = ClipboardFormats.findByAlias(formatName); + if (format == null) { + actor.printError(TranslatableComponent.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); + return; + } + + File f = worldEdit.getSafeSaveFile(actor, dir, filename, format.getPrimaryFileExtension()); + + boolean overwrite = f.exists(); + if (overwrite) { + if (!actor.hasPermission("worldedit.schematic.delete")) { + throw new StopExecutionException(TextComponent.of("That schematic already exists!")); + } + if (!allowOverwrite) { + actor.printError(TranslatableComponent.of("worldedit.schematic.save.already-exists")); + return; + } + } + + // Create parent directories + File parent = f.getParentFile(); + if (parent != null && !parent.exists()) { + if (!parent.mkdirs()) { + throw new StopExecutionException(TranslatableComponent.of( + "worldedit.schematic.save.failed-directory")); + } + } + + ClipboardHolder holder = session.getClipboard(); + + SchematicSaveTask task = new SchematicSaveTask(actor, f, format, holder, overwrite); + AsyncCommandBuilder.wrap(task, actor) + .registerWithSupervisor(worldEdit.getSupervisor(), "Saving schematic " + filename) + .setDelayMessage(TranslatableComponent.of("worldedit.schematic.save.saving")) + .setWorkingMessage(TranslatableComponent.of("worldedit.schematic.save.still-saving")) + .onSuccess(filename + " saved" + (overwrite ? " (overwriting previous file)." : "."), null) + .onFailure("Failed to save schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter()) + .buildAndExec(worldEdit.getExecutorService()); + } + + @Command( + name = "delete", + aliases = {"d"}, + desc = "Delete a saved schematic" + ) + @CommandPermissions("worldedit.schematic.delete") + public void delete(Actor actor, + @Arg(desc = "File name.") + String filename) throws WorldEditException { + LocalConfiguration config = worldEdit.getConfiguration(); + File dir = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); + + File f = worldEdit.getSafeOpenFile(actor, + dir, filename, "schematic", ClipboardFormats.getFileExtensionArray()); + + if (!f.exists()) { + actor.printError(TranslatableComponent.of("worldedit.schematic.delete.does-not-exist", TextComponent.of(filename))); + return; + } + + if (!f.delete()) { + actor.printError(TranslatableComponent.of("worldedit.schematic.delete.failed", TextComponent.of(filename))); + return; + } + + actor.printInfo(TranslatableComponent.of("worldedit.schematic.delete.deleted", TextComponent.of(filename))); + try { + LOGGER.info(actor.getName() + " deleted " + f.getCanonicalPath()); + } catch (IOException e) { + LOGGER.info(actor.getName() + " deleted " + f.getAbsolutePath()); + } + } + + @Command( + name = "formats", + aliases = {"listformats", "f"}, + desc = "List available formats" + ) + @CommandPermissions("worldedit.schematic.formats") + public void formats(Actor actor) { + actor.printInfo(TranslatableComponent.of("worldedit.schematic.formats.title")); + StringBuilder builder; + boolean first = true; + for (ClipboardFormat format : ClipboardFormats.getAll()) { + builder = new StringBuilder(); + builder.append(format.getName()).append(": "); + for (String lookupName : format.getAliases()) { + if (!first) { + builder.append(", "); + } + builder.append(lookupName); + first = false; + } + first = true; + actor.printInfo(TextComponent.of(builder.toString())); + } + } + + @Command( + name = "list", + aliases = {"all", "ls"}, + desc = "List saved schematics", + descFooter = "Note: Format is not fully verified until loading." + ) + @CommandPermissions("worldedit.schematic.list") + public void list(Actor actor, + @ArgFlag(name = 'p', desc = "Page to view.", def = "1") + int page, + @Switch(name = 'd', desc = "Sort by date, oldest first") + boolean oldFirst, + @Switch(name = 'n', desc = "Sort by date, newest first") + boolean newFirst) { + if (oldFirst && newFirst) { + throw new StopExecutionException(TextComponent.of("Cannot sort by oldest and newest.")); + } + final String saveDir = worldEdit.getConfiguration().saveDir; + Comparator pathComparator; + String flag; + if (oldFirst) { + pathComparator = MorePaths.oldestFirst(); + flag = " -d"; + } else if (newFirst) { + pathComparator = MorePaths.newestFirst(); + flag = " -n"; + } else { + pathComparator = Comparator.naturalOrder(); + flag = ""; + } + final String pageCommand = actor.isPlayer() + ? "//schem list -p %page%" + flag : null; + + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, + new SchematicListTask(saveDir, pathComparator, page, pageCommand), + SubtleFormat.wrap("(Please wait... gathering schematic list.)")); + } + + private static class SchematicLoadTask implements Callable { + private final Actor actor; + private final File file; + private final ClipboardFormat format; + + SchematicLoadTask(Actor actor, File file, ClipboardFormat format) { + this.actor = actor; + this.file = file; + this.format = format; + } + + @Override + public ClipboardHolder call() throws Exception { + try (Closer closer = Closer.create()) { + FileInputStream fis = closer.register(new FileInputStream(file)); + BufferedInputStream bis = closer.register(new BufferedInputStream(fis)); + ClipboardReader reader = closer.register(format.getReader(bis)); + + Clipboard clipboard = reader.read(); + LOGGER.info(actor.getName() + " loaded " + file.getCanonicalPath()); + return new ClipboardHolder(clipboard); + } + } + } + + private static class SchematicSaveTask implements Callable { + private final Actor actor; + private final File file; + private final ClipboardFormat format; + private final ClipboardHolder holder; + private final boolean overwrite; + + SchematicSaveTask(Actor actor, File file, ClipboardFormat format, ClipboardHolder holder, boolean overwrite) { + this.actor = actor; + this.file = file; + this.format = format; + this.holder = holder; + this.overwrite = overwrite; + } + + @Override + public Void call() throws Exception { + Clipboard clipboard = holder.getClipboard(); + Transform transform = holder.getTransform(); + Clipboard target; + + // If we have a transform, bake it into the copy + if (transform.isIdentity()) { + target = clipboard; + } else { + FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform); + target = new BlockArrayClipboard(result.getTransformedRegion()); + target.setOrigin(clipboard.getOrigin()); + Operations.completeLegacy(result.copyTo(target)); + } + + try (Closer closer = Closer.create()) { + FileOutputStream fos = closer.register(new FileOutputStream(file)); + BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos)); + ClipboardWriter writer = closer.register(format.getWriter(bos)); + writer.write(target); + + LOGGER.info(actor.getName() + " saved " + file.getCanonicalPath() + (overwrite ? " (overwriting previous file)" : "")); + } catch (IOException e) { + file.delete(); + throw new CommandException(TextComponent.of(e.getMessage()), e, ImmutableList.of()); + } + return null; + } + } + + private static class SchematicListTask implements Callable { + private final Comparator pathComparator; + private final int page; + private final Path rootDir; + private final String pageCommand; + + SchematicListTask(String prefix, Comparator pathComparator, int page, String pageCommand) { + this.pathComparator = pathComparator; + this.page = page; + this.rootDir = WorldEdit.getInstance().getWorkingDirectoryPath(prefix); + this.pageCommand = pageCommand; + } + + @Override + public Component call() throws Exception { + Path resolvedRoot = rootDir.toRealPath(); + List fileList = allFiles(resolvedRoot); + + if (fileList.isEmpty()) { + return ErrorFormat.wrap("No schematics found."); + } + + fileList.sort(pathComparator); + + PaginationBox paginationBox = new SchematicPaginationBox(resolvedRoot, fileList, pageCommand); + return paginationBox.create(page); + } + } + + private static List allFiles(Path root) throws IOException { + List pathList = new ArrayList<>(); + try (DirectoryStream stream = Files.newDirectoryStream(root)) { + for (Path path : stream) { + if (Files.isDirectory(path)) { + pathList.addAll(allFiles(path)); + } else { + pathList.add(path); + } + } + } + return pathList; + } + + private static class SchematicPaginationBox extends PaginationBox { + private final Path rootDir; + private final List files; + + SchematicPaginationBox(Path rootDir, List files, String pageCommand) { + super("Available schematics", pageCommand); + this.rootDir = rootDir; + this.files = files; + } + + @Override + public Component getComponent(int number) { + checkArgument(number < files.size() && number >= 0); + Path file = files.get(number); + + String format = ClipboardFormats.getFileExtensionMap() + .get(MoreFiles.getFileExtension(file)) + .stream() + .findFirst() + .map(ClipboardFormat::getName) + .orElse("Unknown"); + + boolean inRoot = file.getParent().equals(rootDir); + + String path = inRoot + ? file.getFileName().toString() + : file.toString().substring(rootDir.toString().length()); + + return TextComponent.builder() + .content("") + .append(TextComponent.of("[L]") + .color(TextColor.GOLD) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load \"" + path + "\"")) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load")))) + .append(TextComponent.space()) + .append(TextComponent.of(path) + .color(TextColor.DARK_GREEN) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format)))) + .build(); + } + + @Override + public int getComponentsSize() { + return files.size(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java b/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java new file mode 100644 index 0000000..530f618 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java @@ -0,0 +1,112 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.entity.Player; +import net.kyori.text.TranslatableComponent; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; + +import java.io.File; +import java.util.List; +import java.util.stream.Stream; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; + +/** + * Commands related to scripting. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class ScriptingCommands { + + private final WorldEdit worldEdit; + + /** + * Create a new instance. + * + * @param worldEdit reference to WorldEdit + */ + public ScriptingCommands(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + + @Command( + name = "cs", + desc = "Execute a CraftScript" + ) + @CommandPermissions("worldedit.scripting.execute") + @Logging(ALL) + public void execute(Player player, LocalSession session, + @Arg(desc = "Filename of the CraftScript to load") + String filename, + @Arg(desc = "Arguments to the CraftScript", def = "", variable = true) + List args) throws WorldEditException { + if (!player.hasPermission("worldedit.scripting.execute." + filename)) { + player.printError(TranslatableComponent.of("worldedit.execute.script-permissions")); + return; + } + + session.setLastScript(filename); + + File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir); + File f = worldEdit.getSafeOpenFile(player, dir, filename, "js", "js"); + + worldEdit.runScript(player, f, Stream.concat(Stream.of(filename), args.stream()) + .toArray(String[]::new)); + } + + @Command( + name = ".s", + desc = "Execute last CraftScript" + ) + @CommandPermissions("worldedit.scripting.execute") + @Logging(ALL) + public void executeLast(Player player, LocalSession session, + @Arg(desc = "Arguments to the CraftScript", def = "", variable = true) + List args) throws WorldEditException { + + String lastScript = session.getLastScript(); + + if (!player.hasPermission("worldedit.scripting.execute." + lastScript)) { + player.printError(TranslatableComponent.of("worldedit.execute.script-permissions")); + return; + } + + if (lastScript == null) { + player.printError(TranslatableComponent.of("worldedit.executelast.no-script")); + return; + } + + File dir = worldEdit.getWorkingDirectoryPath(worldEdit.getConfiguration().scriptsDir).toFile(); + File f = worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js"); + + worldEdit.runScript(player, f, Stream.concat(Stream.of(lastScript), args.stream()) + .toArray(String[]::new)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java new file mode 100644 index 0000000..53e5158 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -0,0 +1,712 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.common.base.Strings; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.command.argument.SelectorChoice; +import com.sk89q.worldedit.command.tool.NavigationWand; +import com.sk89q.worldedit.command.tool.SelectionWand; +import com.sk89q.worldedit.command.tool.Tool; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.block.BlockDistributionCounter; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.internal.annotation.Chunk3d; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.annotation.MultiDirection; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.ConvexPolyhedralRegionSelector; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.CylinderRegionSelector; +import com.sk89q.worldedit.regions.selector.EllipsoidRegionSelector; +import com.sk89q.worldedit.regions.selector.ExtendingCuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelectorType; +import com.sk89q.worldedit.regions.selector.SphereRegionSelector; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.component.CommandListBox; +import com.sk89q.worldedit.util.formatting.component.InvalidComponentException; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.component.SubtleFormat; +import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; +import com.sk89q.worldedit.world.storage.ChunkStore; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; +import org.enginehub.piston.exception.StopExecutionException; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; +import static com.sk89q.worldedit.world.storage.ChunkStore.CHUNK_SHIFTS; +import static com.sk89q.worldedit.world.storage.ChunkStore.CHUNK_SHIFTS_Y; + +/** + * Selection commands. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class SelectionCommands { + + private final WorldEdit we; + + public SelectionCommands(WorldEdit we) { + this.we = we; + } + + @Command( + name = "/pos1", + desc = "Set position 1" + ) + @Logging(POSITION) + @CommandPermissions("worldedit.selection.pos") + public void pos1(Actor actor, World world, LocalSession session, + @Arg(desc = "Coordinates to set position 1 to", def = "") + BlockVector3 coordinates) throws WorldEditException { + Location pos; + if (coordinates != null) { + pos = new Location(world, coordinates.toVector3()); + } else if (actor instanceof Locatable) { + pos = ((Locatable) actor).getBlockLocation(); + } else { + actor.printError(TranslatableComponent.of("worldedit.pos.console-require-coords")); + return; + } + + if (!session.getRegionSelector(world).selectPrimary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) { + actor.printError(TranslatableComponent.of("worldedit.pos.already-set")); + return; + } + + session.getRegionSelector(world) + .explainPrimarySelection(actor, session, pos.toVector().toBlockPoint()); + } + + @Command( + name = "/pos2", + desc = "Set position 2" + ) + @Logging(POSITION) + @CommandPermissions("worldedit.selection.pos") + public void pos2(Actor actor, World world, LocalSession session, + @Arg(desc = "Coordinates to set position 2 to", def = "") + BlockVector3 coordinates) throws WorldEditException { + Location pos; + if (coordinates != null) { + pos = new Location(world, coordinates.toVector3()); + } else if (actor instanceof Locatable) { + pos = ((Locatable) actor).getBlockLocation(); + } else { + actor.printError(TranslatableComponent.of("worldedit.pos.console-require-coords")); + return; + } + + if (!session.getRegionSelector(world).selectSecondary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) { + actor.printError(TranslatableComponent.of("worldedit.pos.already-set")); + return; + } + + session.getRegionSelector(world) + .explainSecondarySelection(actor, session, pos.toVector().toBlockPoint()); + } + + @Command( + name = "/hpos1", + desc = "Set position 1 to targeted block" + ) + @CommandPermissions("worldedit.selection.hpos") + public void hpos1(Player player, LocalSession session) throws WorldEditException { + + Location pos = player.getBlockTrace(300); + + if (pos != null) { + if (!session.getRegionSelector(player.getWorld()).selectPrimary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(player))) { + player.printError(TranslatableComponent.of("worldedit.hpos.already-set")); + return; + } + + session.getRegionSelector(player.getWorld()) + .explainPrimarySelection(player, session, pos.toVector().toBlockPoint()); + } else { + player.printError(TranslatableComponent.of("worldedit.hpos.no-block")); + } + } + + @Command( + name = "/hpos2", + desc = "Set position 2 to targeted block" + ) + @CommandPermissions("worldedit.selection.hpos") + public void hpos2(Player player, LocalSession session) throws WorldEditException { + + Location pos = player.getBlockTrace(300); + + if (pos != null) { + if (!session.getRegionSelector(player.getWorld()).selectSecondary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(player))) { + player.printError(TranslatableComponent.of("worldedit.hpos.already-set")); + return; + } + + session.getRegionSelector(player.getWorld()) + .explainSecondarySelection(player, session, pos.toVector().toBlockPoint()); + } else { + player.printError(TranslatableComponent.of("worldedit.hpos.no-block")); + } + } + + @Command( + name = "/chunk", + desc = "Set the selection to your current chunk.", + descFooter = "This command selects 256-block-tall areas,\nwhich can be specified by the y-coordinate.\nE.g. -c x,1,z will select from y=256 to y=511." + ) + @Logging(POSITION) + @CommandPermissions("worldedit.selection.chunk") + public void chunk(Actor actor, World world, LocalSession session, + @Arg(desc = "The chunk to select", def = "") + @Chunk3d + BlockVector3 coordinates, + @Switch(name = 's', desc = "Expand your selection to encompass all chunks that are part of it") + boolean expandSelection, + @Switch(name = 'c', desc = "Use chunk coordinates instead of block coordinates") + boolean useChunkCoordinates) throws WorldEditException { + final BlockVector3 min; + final BlockVector3 max; + if (expandSelection) { + Region region = session.getSelection(world); + + int minChunkY = world.getMinY() >> CHUNK_SHIFTS_Y; + int maxChunkY = world.getMaxY() >> CHUNK_SHIFTS_Y; + + BlockVector3 minChunk = ChunkStore.toChunk3d(region.getMinimumPoint()) + .clampY(minChunkY, maxChunkY); + BlockVector3 maxChunk = ChunkStore.toChunk3d(region.getMaximumPoint()) + .clampY(minChunkY, maxChunkY); + + min = minChunk.shl(CHUNK_SHIFTS, CHUNK_SHIFTS_Y, CHUNK_SHIFTS); + max = maxChunk.shl(CHUNK_SHIFTS, CHUNK_SHIFTS_Y, CHUNK_SHIFTS).add(15, 255, 15); + + actor.printInfo(TranslatableComponent.of( + "worldedit.chunk.selected-multiple", + TextComponent.of(minChunk.getBlockX()), + TextComponent.of(minChunk.getBlockY()), + TextComponent.of(minChunk.getBlockZ()), + TextComponent.of(maxChunk.getBlockX()), + TextComponent.of(maxChunk.getBlockY()), + TextComponent.of(maxChunk.getBlockZ()) + )); + } else { + BlockVector3 minChunk; + if (coordinates != null) { + // coords specified + minChunk = useChunkCoordinates + ? coordinates + : ChunkStore.toChunk3d(coordinates); + } else { + // use player loc + if (actor instanceof Locatable) { + minChunk = ChunkStore.toChunk3d(((Locatable) actor).getBlockLocation().toVector().toBlockPoint()); + } else { + throw new StopExecutionException(TextComponent.of("A player or coordinates are required.")); + } + } + + min = minChunk.shl(CHUNK_SHIFTS, CHUNK_SHIFTS_Y, CHUNK_SHIFTS); + max = min.add(15, 255, 15); + + actor.printInfo(TranslatableComponent.of("worldedit.chunk.selected", + TextComponent.of(minChunk.getBlockX()), + TextComponent.of(minChunk.getBlockY()), + TextComponent.of(minChunk.getBlockZ()))); + } + + final CuboidRegionSelector selector; + if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) { + selector = new ExtendingCuboidRegionSelector(world); + } else { + selector = new CuboidRegionSelector(world); + } + selector.selectPrimary(min, ActorSelectorLimits.forActor(actor)); + selector.selectSecondary(max, ActorSelectorLimits.forActor(actor)); + session.setRegionSelector(world, selector); + + session.dispatchCUISelection(actor); + + } + + @Command( + name = "/wand", + desc = "Get the wand item", + descFooter = "You must have also have permission to use at least one of the" + + " features of the requested wand." + ) + @CommandPermissions("worldedit.wand") + public void wand(Player player, LocalSession session, + @Switch(name = 'n', desc = "Get a navigation wand") + boolean navWand) throws WorldEditException { + Tool tool = navWand ? new NavigationWand() : new SelectionWand(); + if (!tool.canUse(player)) { + player.printError(TranslatableComponent.of("worldedit.command.permissions")); + return; + } + String wandId = navWand ? session.getNavWandItem() : session.getWandItem(); + if (wandId == null) { + wandId = navWand ? we.getConfiguration().navigationWand : we.getConfiguration().wandItem; + } + ItemType itemType = ItemTypes.get(wandId); + if (itemType == null) { + player.printError(TranslatableComponent.of("worldedit.wand.invalid")); + return; + } + player.giveItem(new BaseItemStack(itemType, 1)); + session.setTool(itemType, tool); + player.printInfo(TranslatableComponent.of("worldedit.wand." + (navWand ? "nav" : "sel" ) + "wand.info")); + } + + @Command( + name = "toggleeditwand", + desc = "Remind the user that the wand is now a tool and can be unbound with /tool none." + ) + @CommandPermissions("worldedit.wand.toggle") + public void toggleWand(Player player) { + player.printInfo( + TranslatableComponent.of( + "worldedit.wand.selwand.now.tool", + TextComponent.of("/tool none", TextColor.AQUA).clickEvent( + ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/tool none")), + TextComponent.of("/tool selwand", TextColor.AQUA).clickEvent( + ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/tool selwand")), + TextComponent.of("//wand", TextColor.AQUA).clickEvent( + ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//wand")) + ) + ); + } + + @Command( + name = "/contract", + desc = "Contract the selection area" + ) + @Logging(REGION) + @CommandPermissions("worldedit.selection.contract") + public void contract(Actor actor, World world, LocalSession session, + @Arg(desc = "Amount to contract the selection by") + int amount, + @Arg(desc = "Amount to contract the selection by in the other direction", def = "0") + int reverseAmount, + @Arg(desc = "Direction to contract", def = Direction.AIM) + @MultiDirection + List direction) throws WorldEditException { + try { + Region region = session.getSelection(world); + long oldSize = region.getVolume(); + if (reverseAmount == 0) { + for (BlockVector3 dir : direction) { + region.contract(dir.multiply(amount)); + } + } else { + for (BlockVector3 dir : direction) { + region.contract(dir.multiply(amount), dir.multiply(-reverseAmount)); + } + } + session.getRegionSelector(world).learnChanges(); + long newSize = region.getVolume(); + + session.getRegionSelector(world).explainRegionAdjust(actor, session); + + actor.printInfo(TranslatableComponent.of("worldedit.contract.contracted", TextComponent.of(oldSize - newSize))); + } catch (RegionOperationException e) { + actor.printError(TextComponent.of(e.getMessage())); + } + } + + @Command( + name = "/shift", + desc = "Shift the selection area" + ) + @Logging(REGION) + @CommandPermissions("worldedit.selection.shift") + public void shift(Actor actor, World world, LocalSession session, + @Arg(desc = "Amount to shift the selection by") + int amount, + @Arg(desc = "Direction to contract", def = Direction.AIM) + @MultiDirection + List direction) throws WorldEditException { + try { + Region region = session.getSelection(world); + + for (BlockVector3 dir : direction) { + region.shift(dir.multiply(amount)); + } + + session.getRegionSelector(world).learnChanges(); + + session.getRegionSelector(world).explainRegionAdjust(actor, session); + + actor.printInfo(TranslatableComponent.of("worldedit.shift.shifted")); + } catch (RegionOperationException e) { + actor.printError(TextComponent.of(e.getMessage())); + } + } + + @Command( + name = "/outset", + desc = "Outset the selection area" + ) + @Logging(REGION) + @CommandPermissions("worldedit.selection.outset") + public void outset(Actor actor, World world, LocalSession session, + @Arg(desc = "Amount to expand the selection by in all directions") + int amount, + @Switch(name = 'h', desc = "Only expand horizontally") + boolean onlyHorizontal, + @Switch(name = 'v', desc = "Only expand vertically") + boolean onlyVertical) throws WorldEditException { + Region region = session.getSelection(world); + region.expand(getChangesForEachDir(amount, onlyHorizontal, onlyVertical)); + session.getRegionSelector(world).learnChanges(); + session.getRegionSelector(world).explainRegionAdjust(actor, session); + actor.printInfo(TranslatableComponent.of("worldedit.outset.outset")); + } + + @Command( + name = "/inset", + desc = "Inset the selection area" + ) + @Logging(REGION) + @CommandPermissions("worldedit.selection.inset") + public void inset(Actor actor, World world, LocalSession session, + @Arg(desc = "Amount to contract the selection by in all directions") + int amount, + @Switch(name = 'h', desc = "Only contract horizontally") + boolean onlyHorizontal, + @Switch(name = 'v', desc = "Only contract vertically") + boolean onlyVertical) throws WorldEditException { + Region region = session.getSelection(world); + region.contract(getChangesForEachDir(amount, onlyHorizontal, onlyVertical)); + session.getRegionSelector(world).learnChanges(); + session.getRegionSelector(world).explainRegionAdjust(actor, session); + actor.printInfo(TranslatableComponent.of("worldedit.inset.inset")); + } + + private BlockVector3[] getChangesForEachDir(int amount, boolean onlyHorizontal, boolean onlyVertical) { + Stream.Builder changes = Stream.builder(); + + if (!onlyHorizontal) { + changes.add(BlockVector3.UNIT_Y); + changes.add(BlockVector3.UNIT_MINUS_Y); + } + + if (!onlyVertical) { + changes.add(BlockVector3.UNIT_X); + changes.add(BlockVector3.UNIT_MINUS_X); + changes.add(BlockVector3.UNIT_Z); + changes.add(BlockVector3.UNIT_MINUS_Z); + } + + return changes.build().map(v -> v.multiply(amount)).toArray(BlockVector3[]::new); + } + + @Command( + name = "/size", + desc = "Get information about the selection" + ) + @CommandPermissions("worldedit.selection.size") + public void size(Actor actor, World world, LocalSession session, + @Switch(name = 'c', desc = "Get clipboard info instead") + boolean clipboardInfo) throws WorldEditException { + Region region; + if (clipboardInfo) { + ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); + region = clipboard.getRegion(); + + BlockVector3 origin = clipboard.getOrigin(); + actor.printInfo(TranslatableComponent.of("worldedit.size.offset", TextComponent.of(origin.toString()))); + } else { + region = session.getSelection(world); + + actor.printInfo(TranslatableComponent.of("worldedit.size.type", TextComponent.of(session.getRegionSelector(world).getTypeName()))); + + for (Component line : session.getRegionSelector(world).getSelectionInfoLines()) { + actor.printInfo(line); + } + } + BlockVector3 size = region.getMaximumPoint() + .subtract(region.getMinimumPoint()) + .add(1, 1, 1); + + actor.printInfo(TranslatableComponent.of("worldedit.size.size", TextComponent.of(size.toString()))); + actor.printInfo(TranslatableComponent.of("worldedit.size.distance", TextComponent.of(region.getMaximumPoint().distance(region.getMinimumPoint())))); + actor.printInfo(TranslatableComponent.of("worldedit.size.blocks", TextComponent.of(region.getVolume()))); + } + + @Command( + name = "/count", + desc = "Counts the number of blocks matching a mask" + ) + @CommandPermissions("worldedit.analysis.count") + public int count(Actor actor, World world, LocalSession session, EditSession editSession, + @Arg(desc = "The mask of blocks to match") + Mask mask) throws WorldEditException { + int count = editSession.countBlocks(session.getSelection(world), mask); + actor.printInfo(TranslatableComponent.of("worldedit.count.counted", TextComponent.of(count))); + return count; + } + + @Command( + name = "/distr", + desc = "Get the distribution of blocks in the selection" + ) + @CommandPermissions("worldedit.analysis.distr") + public void distr(Actor actor, World world, LocalSession session, + @Switch(name = 'c', desc = "Get the distribution of the clipboard instead") + boolean clipboardDistr, + @Switch(name = 'd', desc = "Separate blocks by state") + boolean separateStates, + @ArgFlag(name = 'p', desc = "Gets page from a previous distribution.") + Integer page) throws WorldEditException { + List> distribution; + + if (page == null) { + if (clipboardDistr) { + Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing + BlockDistributionCounter count = new BlockDistributionCounter(clipboard, separateStates); + RegionVisitor visitor = new RegionVisitor(clipboard.getRegion(), count); + Operations.completeBlindly(visitor); + distribution = count.getDistribution(); + } else { + try (EditSession editSession = session.createEditSession(actor)) { + distribution = editSession.getBlockDistribution(session.getSelection(world), separateStates); + } + } + session.setLastDistribution(distribution); + page = 1; + } else { + distribution = session.getLastDistribution(); + if (distribution == null) { + actor.printError(TranslatableComponent.of("worldedit.distr.no-previous")); + return; + } + } + + if (distribution.isEmpty()) { // *Should* always be false + actor.printError(TranslatableComponent.of("worldedit.distr.no-blocks")); + return; + } + + final int finalPage = page; + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> { + BlockDistributionResult res = new BlockDistributionResult(distribution, separateStates); + if (!actor.isPlayer()) { + res.formatForConsole(); + } + return res.create(finalPage); + }, (Component) null); + } + + @Command( + name = "/sel", + aliases = { ";", "/desel", "/deselect" }, + desc = "Choose a region selector" + ) + public void select(Actor actor, World world, LocalSession session, + @Arg(desc = "Selector to switch to", def = "") + SelectorChoice selector, + @Switch(name = 'd', desc = "Set default selector") + boolean setDefaultSelector) throws WorldEditException { + if (selector == null) { + session.getRegionSelector(world).clear(); + session.dispatchCUISelection(actor); + actor.printInfo(TranslatableComponent.of("worldedit.select.cleared")); + return; + } + + final RegionSelector oldSelector = session.getRegionSelector(world); + + final RegionSelector newSelector; + switch (selector) { + case CUBOID: + newSelector = new CuboidRegionSelector(oldSelector); + actor.printInfo(TranslatableComponent.of("worldedit.select.cuboid.message")); + break; + case EXTEND: + newSelector = new ExtendingCuboidRegionSelector(oldSelector); + actor.printInfo(TranslatableComponent.of("worldedit.select.extend.message")); + break; + case POLY: { + newSelector = new Polygonal2DRegionSelector(oldSelector); + actor.printInfo(TranslatableComponent.of("worldedit.select.poly.message")); + Optional limit = ActorSelectorLimits.forActor(actor).getPolygonVertexLimit(); + limit.ifPresent(integer -> actor.printInfo(TranslatableComponent.of("worldedit.select.poly.limit-message", TextComponent.of(integer)))); + break; + } + case ELLIPSOID: + newSelector = new EllipsoidRegionSelector(oldSelector); + actor.printInfo(TranslatableComponent.of("worldedit.select.ellipsoid.message")); + break; + case SPHERE: + newSelector = new SphereRegionSelector(oldSelector); + actor.printInfo(TranslatableComponent.of("worldedit.select.sphere.message")); + break; + case CYL: + newSelector = new CylinderRegionSelector(oldSelector); + actor.printInfo(TranslatableComponent.of("worldedit.select.cyl.message")); + break; + case CONVEX: + case HULL: + case POLYHEDRON: { + newSelector = new ConvexPolyhedralRegionSelector(oldSelector); + actor.printInfo(TranslatableComponent.of("worldedit.select.convex.message")); + Optional limit = ActorSelectorLimits.forActor(actor).getPolyhedronVertexLimit(); + limit.ifPresent(integer -> actor.printInfo(TranslatableComponent.of("worldedit.select.convex.limit-message", TextComponent.of(integer)))); + break; + } + case LIST: + default: + CommandListBox box = new CommandListBox("Selection modes", null, null); + box.setHidingHelp(true); + TextComponentProducer contents = box.getContents(); + contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline(); + + box.appendCommand("cuboid", TranslatableComponent.of("worldedit.select.cuboid.description"), "//sel cuboid"); + box.appendCommand("extend", TranslatableComponent.of("worldedit.select.extend.description"), "//sel extend"); + box.appendCommand("poly", TranslatableComponent.of("worldedit.select.poly.description"), "//sel poly"); + box.appendCommand("ellipsoid", TranslatableComponent.of("worldedit.select.ellipsoid.description"), "//sel ellipsoid"); + box.appendCommand("sphere", TranslatableComponent.of("worldedit.select.sphere.description"), "//sel sphere"); + box.appendCommand("cyl", TranslatableComponent.of("worldedit.select.cyl.description"), "//sel cyl"); + box.appendCommand("convex", TranslatableComponent.of("worldedit.select.convex.description"), "//sel convex"); + + actor.print(box.create(1)); + return; + } + + if (setDefaultSelector) { + RegionSelectorType found = null; + for (RegionSelectorType type : RegionSelectorType.values()) { + if (type.getSelectorClass() == newSelector.getClass()) { + found = type; + break; + } + } + + if (found != null) { + session.setDefaultRegionSelector(found); + actor.printInfo(TranslatableComponent.of("worldedit.select.default-set", TextComponent.of(found.name()))); + } else { + throw new RuntimeException("Something unexpected happened. Please report this."); + } + } + + session.setRegionSelector(world, newSelector); + session.dispatchCUISelection(actor); + } + + private static class BlockDistributionResult extends PaginationBox { + + private final List> distribution; + private final int totalBlocks; + private final boolean separateStates; + + BlockDistributionResult(List> distribution, boolean separateStates) { + super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : "")); + this.distribution = distribution; + // note: doing things like region.getArea is inaccurate for non-cuboids. + this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum(); + this.separateStates = separateStates; + setComponentsPerPage(7); + } + + @Override + public Component getComponent(int number) { + Countable c = distribution.get(number); + TextComponent.Builder line = TextComponent.builder(); + + final int count = c.getAmount(); + + final double perc = count / (double) totalBlocks * 100; + final int maxDigits = (int) (Math.log10(totalBlocks) + 1); + final int curDigits = (int) (Math.log10(count) + 1); + line.append(String.format("%s%.3f%% ", perc < 10 ? " " : "", perc), TextColor.GOLD); + final int space = maxDigits - curDigits; + String pad = Strings.repeat(" ", space == 0 ? 2 : 2 * space + 1); + line.append(String.format("%s%s", count, pad), TextColor.YELLOW); + + final BlockState state = c.getID(); + final BlockType blockType = state.getBlockType(); + Component blockName = blockType.getRichName().color(TextColor.LIGHT_PURPLE); + TextComponent toolTip; + if (separateStates && state != blockType.getDefaultState()) { + toolTip = TextComponent.of(state.getAsString(), TextColor.GRAY); + blockName = blockName.append(TextComponent.of("*", TextColor.LIGHT_PURPLE)); + } else { + toolTip = TextComponent.of(blockType.getId(), TextColor.GRAY); + } + blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip)); + line.append(blockName); + + return line.build(); + } + + @Override + public int getComponentsSize() { + return distribution.size(); + } + + @Override + public Component create(int page) throws InvalidComponentException { + super.getContents().append(TranslatableComponent.of("worldedit.distr.total", TextColor.GRAY, TextComponent.of(totalBlocks))) + .append(TextComponent.newline()); + return super.create(page); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java b/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java new file mode 100644 index 0000000..8f5ccae --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java @@ -0,0 +1,344 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.snapshot.experimental.Snapshot; +import com.sk89q.worldedit.world.snapshot.experimental.fs.FileSystemSnapshotDatabase; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.exception.StopExecutionException; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toList; + +/** + * Snapshot commands. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class SnapshotCommands { + + private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z"); + + private final WorldEdit we; + private final LegacySnapshotCommands legacy; + + public SnapshotCommands(WorldEdit we) { + this.we = we; + this.legacy = new LegacySnapshotCommands(we); + } + + static void checkSnapshotsConfigured(LocalConfiguration localConfiguration) { + if (!localConfiguration.snapshotsConfigured) { + throw new StopExecutionException(TranslatableComponent.of( + "worldedit.restore.not-configured" + )); + } + } + + static URI resolveSnapshotName(LocalConfiguration config, String name) { + if (!name.contains("://")) { + if (config.snapshotDatabase instanceof FileSystemSnapshotDatabase) { + String newName = name; + while (newName.startsWith("/")) { + newName = newName.substring(1); + } + return FileSystemSnapshotDatabase.createUri(newName); + } + } + return URI.create(name); + } + + + @Command( + name = "list", + desc = "List snapshots" + ) + @CommandPermissions("worldedit.snapshots.list") + void list(Actor actor, World world, + @ArgFlag(name = 'p', desc = "Page of results to return", def = "1") + int page) throws WorldEditException, IOException { + LocalConfiguration config = we.getConfiguration(); + checkSnapshotsConfigured(config); + + if (config.snapshotRepo != null) { + legacy.list(actor, world, page); + return; + } + + List snapshots; + try (Stream snapshotStream = + config.snapshotDatabase.getSnapshotsNewestFirst(world.getName())) { + snapshots = snapshotStream + .collect(toList()); + } + + if (!snapshots.isEmpty()) { + actor.print(new SnapshotListBox(world.getName(), snapshots).create(page)); + } else { + actor.printError(TranslatableComponent.of( + "worldedit.restore.none-for-specific-world", + TextComponent.of(world.getName()) + )); + + if (config.snapshotDatabase instanceof FileSystemSnapshotDatabase) { + FileSystemSnapshotDatabase db = (FileSystemSnapshotDatabase) config.snapshotDatabase; + Path root = db.getRoot(); + if (Files.isDirectory(root)) { + WorldEdit.logger.info("No snapshots were found for world '" + + world.getName() + "'; looked in " + root.toRealPath()); + } else { + WorldEdit.logger.info("No snapshots were found for world '" + + world.getName() + "'; " + root.toRealPath() + " is not a directory"); + } + } + } + } + + @Command( + name = "use", + desc = "Choose a snapshot to use" + ) + @CommandPermissions("worldedit.snapshots.restore") + void use(Actor actor, World world, LocalSession session, + @Arg(desc = "Snapshot to use") + String name) throws IOException { + LocalConfiguration config = we.getConfiguration(); + checkSnapshotsConfigured(config); + + if (config.snapshotRepo != null) { + legacy.use(actor, world, session, name); + return; + } + + // Want the latest snapshot? + if (name.equalsIgnoreCase("latest")) { + Snapshot snapshot; + try (Stream snapshotStream = + config.snapshotDatabase.getSnapshotsNewestFirst(world.getName())) { + snapshot = snapshotStream + .findFirst().orElse(null); + } + + if (snapshot != null) { + if (session.getSnapshotExperimental() != null) { + session.getSnapshotExperimental().close(); + } + session.setSnapshot(null); + actor.printInfo(TranslatableComponent.of("worldedit.snapshot.use.newest")); + } else { + actor.printError(TranslatableComponent.of("worldedit.restore.none-for-world")); + } + } else { + URI uri = resolveSnapshotName(config, name); + Optional snapshot = config.snapshotDatabase.getSnapshot(uri); + if (snapshot.isPresent()) { + if (session.getSnapshotExperimental() != null) { + session.getSnapshotExperimental().close(); + } + session.setSnapshotExperimental(snapshot.get()); + actor.printInfo(TranslatableComponent.of( + "worldedit.snapshot.use", TextComponent.of(name) + )); + } else { + actor.printError(TranslatableComponent.of("worldedit.restore.not-available")); + } + } + } + + @Command( + name = "sel", + desc = "Choose the snapshot based on the list id" + ) + @CommandPermissions("worldedit.snapshots.restore") + void sel(Actor actor, World world, LocalSession session, + @Arg(desc = "The list ID to select") + int index) throws IOException { + LocalConfiguration config = we.getConfiguration(); + checkSnapshotsConfigured(config); + + if (config.snapshotRepo != null) { + legacy.sel(actor, world, session, index); + return; + } + + if (index < 1) { + actor.printError(TranslatableComponent.of("worldedit.snapshot.index-above-0")); + return; + } + + List snapshots; + try (Stream snapshotStream = + config.snapshotDatabase.getSnapshotsNewestFirst(world.getName())) { + snapshots = snapshotStream + .collect(toList()); + } + if (snapshots.size() < index) { + actor.printError(TranslatableComponent.of( + "worldedit.snapshot.index-oob", + TextComponent.of(snapshots.size()) + )); + return; + } + Snapshot snapshot = snapshots.get(index - 1); + if (snapshot == null) { + actor.printError(TranslatableComponent.of("worldedit.restore.not-available")); + return; + } + if (session.getSnapshotExperimental() != null) { + session.getSnapshotExperimental().close(); + } + session.setSnapshotExperimental(snapshot); + actor.printInfo(TranslatableComponent.of( + "worldedit.snapshot.use", + TextComponent.of(snapshot.getInfo().getDisplayName()) + )); + } + + @Command( + name = "before", + desc = "Choose the nearest snapshot before a date" + ) + @CommandPermissions("worldedit.snapshots.restore") + void before(Actor actor, World world, LocalSession session, + @Arg(desc = "The soonest date that may be used") + ZonedDateTime date) throws IOException { + LocalConfiguration config = we.getConfiguration(); + checkSnapshotsConfigured(config); + + if (config.snapshotRepo != null) { + legacy.before(actor, world, session, date); + return; + } + + Snapshot snapshot; + try (Stream snapshotStream = + config.snapshotDatabase.getSnapshotsNewestFirst(world.getName())) { + snapshot = snapshotStream + .findFirst().orElse(null); + } + + if (snapshot == null) { + actor.printError(TranslatableComponent.of( + "worldedit.snapshot.none-before", + TextComponent.of(dateFormat.withZone(session.getTimeZone()).format(date))) + ); + } else { + if (session.getSnapshotExperimental() != null) { + session.getSnapshotExperimental().close(); + } + session.setSnapshotExperimental(snapshot); + actor.printInfo(TranslatableComponent.of( + "worldedit.snapshot.use", + TextComponent.of(snapshot.getInfo().getDisplayName()) + )); + } + } + + @Command( + name = "after", + desc = "Choose the nearest snapshot after a date" + ) + @CommandPermissions("worldedit.snapshots.restore") + void after(Actor actor, World world, LocalSession session, + @Arg(desc = "The soonest date that may be used") + ZonedDateTime date) throws IOException { + LocalConfiguration config = we.getConfiguration(); + checkSnapshotsConfigured(config); + + if (config.snapshotRepo != null) { + legacy.after(actor, world, session, date); + return; + } + + Snapshot snapshot; + try (Stream snapshotStream = + config.snapshotDatabase.getSnapshotsNewestFirst(world.getName())) { + snapshot = snapshotStream + .findFirst().orElse(null); + } + if (snapshot == null) { + actor.printError(TranslatableComponent.of( + "worldedit.snapshot.none-after", + TextComponent.of(dateFormat.withZone(session.getTimeZone()).format(date))) + ); + } else { + if (session.getSnapshotExperimental() != null) { + session.getSnapshotExperimental().close(); + } + session.setSnapshotExperimental(snapshot); + actor.printInfo(TranslatableComponent.of( + "worldedit.snapshot.use", + TextComponent.of(snapshot.getInfo().getDisplayName()) + )); + } + } + + private static class SnapshotListBox extends PaginationBox { + private final List snapshots; + + SnapshotListBox(String world, List snapshots) { + super("Snapshots for: " + world, "/snap list -p %page%"); + this.snapshots = snapshots; + } + + @Override + public Component getComponent(int number) { + final Snapshot snapshot = snapshots.get(number); + String displayName = snapshot.getInfo().getDisplayName(); + return TextComponent.of(number + 1 + ". ", TextColor.GOLD) + .append(TextComponent.builder(displayName, TextColor.LIGHT_PURPLE) + .hoverEvent(HoverEvent.showText(TextComponent.of("Click to use"))) + .clickEvent(ClickEvent.runCommand("/snap use " + displayName))); + } + + @Override + public int getComponentsSize() { + return snapshots.size(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java b/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java new file mode 100644 index 0000000..a115c79 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java @@ -0,0 +1,140 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.regions.Region; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.snapshot.experimental.Snapshot; +import com.sk89q.worldedit.world.snapshot.experimental.SnapshotRestore; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; + +import java.io.IOException; +import java.net.URI; +import java.util.Optional; +import java.util.stream.Stream; + +import static com.sk89q.worldedit.command.SnapshotCommands.checkSnapshotsConfigured; +import static com.sk89q.worldedit.command.SnapshotCommands.resolveSnapshotName; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; + +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class SnapshotUtilCommands { + + private final WorldEdit we; + private final LegacySnapshotUtilCommands legacy; + + public SnapshotUtilCommands(WorldEdit we) { + this.we = we; + this.legacy = new LegacySnapshotUtilCommands(we); + } + + @Command( + name = "restore", + aliases = { "/restore" }, + desc = "Restore the selection from a snapshot" + ) + @Logging(REGION) + @CommandPermissions("worldedit.snapshots.restore") + public void restore(Actor actor, World world, LocalSession session, EditSession editSession, + @Arg(name = "snapshot", desc = "The snapshot to restore", def = "") + String snapshotName) throws WorldEditException, IOException { + LocalConfiguration config = we.getConfiguration(); + checkSnapshotsConfigured(config); + + if (config.snapshotRepo != null) { + legacy.restore(actor, world, session, editSession, snapshotName); + return; + } + + Region region = session.getSelection(world); + Snapshot snapshot; + + if (snapshotName != null) { + URI uri = resolveSnapshotName(config, snapshotName); + Optional snapOpt = config.snapshotDatabase.getSnapshot(uri); + if (!snapOpt.isPresent()) { + actor.printError(TranslatableComponent.of("worldedit.restore.not-available")); + return; + } + snapshot = snapOpt.get(); + } else { + snapshot = session.getSnapshotExperimental(); + } + + // No snapshot set? + if (snapshot == null) { + try (Stream snapshotStream = + config.snapshotDatabase.getSnapshotsNewestFirst(world.getName())) { + snapshot = snapshotStream + .findFirst().orElse(null); + } + + if (snapshot == null) { + actor.printError(TranslatableComponent.of( + "worldedit.restore.none-for-specific-world", + TextComponent.of(world.getName()) + )); + return; + } + } + actor.printInfo(TranslatableComponent.of( + "worldedit.restore.loaded", + TextComponent.of(snapshot.getInfo().getDisplayName()) + )); + + try { + // Restore snapshot + SnapshotRestore restore = new SnapshotRestore(snapshot, editSession, region); + //player.print(restore.getChunksAffected() + " chunk(s) will be loaded."); + + restore.restore(); + + if (restore.hadTotalFailure()) { + String error = restore.getLastErrorMessage(); + if (!restore.getMissingChunks().isEmpty()) { + actor.printError(TranslatableComponent.of("worldedit.restore.chunk-not-present")); + } else if (error != null) { + actor.printError(TranslatableComponent.of("worldedit.restore.block-place-failed")); + actor.printError(TranslatableComponent.of("worldedit.restore.block-place-error", TextComponent.of(error))); + } else { + actor.printError(TranslatableComponent.of("worldedit.restore.chunk-load-failed")); + } + } else { + actor.printInfo(TranslatableComponent.of("worldedit.restore.restored", + TextComponent.of(restore.getMissingChunks().size()), + TextComponent.of(restore.getErrorChunks().size()))); + } + } finally { + try { + snapshot.close(); + } catch (IOException ignored) { + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java b/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java new file mode 100644 index 0000000..16af5f7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java @@ -0,0 +1,99 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.tool.AreaPickaxe; +import com.sk89q.worldedit.command.tool.RecursivePickaxe; +import com.sk89q.worldedit.command.tool.SinglePickaxe; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.entity.Player; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; + +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class SuperPickaxeCommands { + private final WorldEdit we; + + public SuperPickaxeCommands(WorldEdit we) { + this.we = we; + } + + @Command( + name = "single", + desc = "Enable the single block super pickaxe mode" + ) + @CommandPermissions("worldedit.superpickaxe") + public void single(Player player, LocalSession session) throws WorldEditException { + session.setSuperPickaxe(new SinglePickaxe()); + session.enableSuperPickAxe(); + player.printInfo(TranslatableComponent.of("worldedit.tool.superpickaxe.mode.single")); + } + + @Command( + name = "area", + desc = "Enable the area super pickaxe pickaxe mode" + ) + @CommandPermissions("worldedit.superpickaxe.area") + public void area(Player player, LocalSession session, + @Arg(desc = "The range of the area pickaxe") + int range) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + if (range > config.maxSuperPickaxeSize) { + player.printError(TranslatableComponent.of("worldedit.tool.superpickaxe.max-range", TextComponent.of(config.maxSuperPickaxeSize))); + return; + } + + session.setSuperPickaxe(new AreaPickaxe(range)); + session.enableSuperPickAxe(); + player.printInfo(TranslatableComponent.of("worldedit.tool.superpickaxe.mode.area")); + } + + @Command( + name = "recursive", + aliases = { "recur" }, + desc = "Enable the recursive super pickaxe pickaxe mode" + ) + @CommandPermissions("worldedit.superpickaxe.recursive") + public void recursive(Player player, LocalSession session, + @Arg(desc = "The range of the recursive pickaxe") + double range) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + if (range > config.maxSuperPickaxeSize) { + player.printError(TranslatableComponent.of("worldedit.tool.superpickaxe.max-range", TextComponent.of(config.maxSuperPickaxeSize))); + return; + } + + session.setSuperPickaxe(new RecursivePickaxe(range)); + session.enableSuperPickAxe(); + player.printInfo(TranslatableComponent.of("worldedit.tool.superpickaxe.mode.recursive")); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/src/main/java/com/sk89q/worldedit/command/ToolCommands.java new file mode 100644 index 0000000..3249ebb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -0,0 +1,310 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.common.collect.Collections2; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.command.tool.*; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.SubCommandPermissionCondition; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.internal.command.CommandUtil; +import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.TreeGenerator; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.item.ItemType; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandManagerService; +import org.enginehub.piston.CommandMetadata; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.part.SubCommandPart; + +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class ToolCommands { + + private static final Component UNBIND_COMMAND_COMPONENT = TextComponent.builder("/tool unbind", TextColor.AQUA) + .clickEvent(ClickEvent.suggestCommand("/tool unbind")) + .build(); + + public static void register(CommandRegistrationHandler registration, + CommandManager commandManager, + CommandManagerService commandManagerService, + WorldEdit worldEdit) { + // Collect the tool commands + CommandManager collect = commandManagerService.newCommandManager(); + + registration.register( + collect, + ToolCommandsRegistration.builder(), + new ToolCommands(worldEdit) + ); + + // Register deprecated global commands + Set commands = collect.getAllCommands() + .collect(Collectors.toSet()); + for (org.enginehub.piston.Command command : commands) { + if (command.getAliases().contains("unbind")) { + // Don't register new /tool alias + command = command.toBuilder().aliases( + Collections2.filter(command.getAliases(), alias -> !"unbind".equals(alias)) + ).build(); + } + if (command.getName().equals("stacker")) { + // Don't register /stacker + continue; + } + commandManager.register(CommandUtil.deprecate( + command, "Global tool names cause conflicts " + + "and will be removed in WorldEdit 8", + CommandUtil.ReplacementMessageGenerator.forNewCommand(ToolCommands::asNonGlobal) + )); + } + + // Remove aliases with / in them, since it doesn't make sense for sub-commands. + Set nonGlobalCommands = commands.stream() + .map(command -> + command.toBuilder().aliases( + Collections2.filter(command.getAliases(), alias -> !alias.startsWith("/")) + ).build() + ) + .collect(Collectors.toSet()); + commandManager.register("tool", command -> { + command.addPart(SubCommandPart.builder( + TranslatableComponent.of("tool"), + TextComponent.of("The tool to bind") + ) + .withCommands(nonGlobalCommands) + .required() + .build()); + command.description(TextComponent.of("Binds a tool to the item in your hand")); + + command.condition(new SubCommandPermissionCondition.Generator(nonGlobalCommands).build()); + }); + } + + private static String asNonGlobal(org.enginehub.piston.Command oldCommand, + CommandParameters oldParameters) { + String name = Optional.ofNullable(oldParameters.getMetadata()) + .map(CommandMetadata::getCalledName) + .filter(n -> !n.startsWith("/")) + .orElseGet(oldCommand::getName); + return "/tool " + name; + } + + static void setToolNone(Player player, LocalSession session, boolean isBrush) + throws InvalidToolBindException { + ItemType type = player.getItemInHand(HandSide.MAIN_HAND).getType(); + boolean set = session.getTool(type) != null + || type.getId().equals(session.getWandItem()) + || type.getId().equals(session.getNavWandItem()); + if (set) { + session.setTool(type, null); + player.printInfo(TranslatableComponent.of(isBrush ? "worldedit.brush.none.equip" : "worldedit.tool.none.equip")); + } else { + player.printInfo(TranslatableComponent.of("worldedit.tool.none.to.unequip")); + } + } + + static void sendUnbindInstruction(Player sender, Component commandComponent) { + sender.printDebug(TranslatableComponent.of("worldedit.tool.unbind-instruction", commandComponent)); + } + + private static void setTool(Player player, LocalSession session, Tool tool, + String translationKey) throws InvalidToolBindException { + BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); + session.setTool(itemStack.getType(), tool); + player.printInfo(TranslatableComponent.of(translationKey, itemStack.getRichName())); + sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); + } + + private final WorldEdit we; + + public ToolCommands(WorldEdit we) { + this.we = we; + } + + @Command( + name = "none", + aliases = "unbind", + desc = "Unbind a bound tool from your current item" + ) + public void none(Player player, LocalSession session) throws WorldEditException { + setToolNone(player, session, false); + } + + @Command( + name = "selwand", + aliases = "/selwand", + desc = "Selection wand tool" + ) + @CommandPermissions("worldedit.setwand") + public void selwand(Player player, LocalSession session) throws WorldEditException { + setTool(player, session, new SelectionWand(), "worldedit.tool.selwand.equip"); + } + + @Command( + name = "navwand", + aliases = "/navwand", + desc = "Navigation wand tool" + ) + @CommandPermissions("worldedit.setwand") + public void navwand(Player player, LocalSession session) throws WorldEditException { + setTool(player, session, new NavigationWand(), "worldedit.tool.navwand.equip"); + } + + @Command( + name = "info", + desc = "Block information tool" + ) + @CommandPermissions("worldedit.tool.info") + public void info(Player player, LocalSession session) throws WorldEditException { + setTool(player, session, new QueryTool(), "worldedit.tool.info.equip"); + } + + @Command( + name = "tree", + desc = "Tree generator tool" + ) + @CommandPermissions("worldedit.tool.tree") + public void tree(Player player, LocalSession session, + @Arg(desc = "Type of tree to generate", def = "tree") + TreeGenerator.TreeType type) throws WorldEditException { + setTool(player, session, new TreePlanter(type), "worldedit.tool.tree.equip"); + } + + @Command( + name = "stacker", + desc = "Block stacker tool" + ) + @CommandPermissions("worldedit.tool.stack") + public void stacker(Player player, LocalSession session, + @Arg(desc = "The max range of the stack", def = "10") + int range, + @Arg(desc = "The mask to stack until", def = "!#existing") + Mask mask) throws WorldEditException { + setTool(player, session, new StackTool(range, mask), "worldedit.tool.stack.equip"); + } + + @Command( + name = "repl", + desc = "Block replacer tool" + ) + @CommandPermissions("worldedit.tool.replacer") + public void repl(Player player, LocalSession session, + @Arg(desc = "The pattern of blocks to place") + Pattern pattern) throws WorldEditException { + setTool(player, session, new BlockReplacer(pattern), "worldedit.tool.repl.equip"); + } + + @Command( + name = "cycler", + desc = "Block data cycler tool" + ) + @CommandPermissions("worldedit.tool.data-cycler") + public void cycler(Player player, LocalSession session) throws WorldEditException { + setTool(player, session, new BlockDataCyler(), "worldedit.tool.data-cycler.equip"); + } + + @Command( + name = "floodfill", + aliases = { "flood" }, + desc = "Flood fill tool" + ) + @CommandPermissions("worldedit.tool.flood-fill") + public void floodFill(Player player, LocalSession session, + @Arg(desc = "The pattern to flood fill") + Pattern pattern, + @Arg(desc = "The range to perform the fill") + int range) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + if (range > config.maxSuperPickaxeSize) { + player.printError(TranslatableComponent.of("worldedit.tool.superpickaxe.max-range", TextComponent.of(config.maxSuperPickaxeSize))); + return; + } + setTool(player, session, new FloodFillTool(range, pattern), "worldedit.tool.floodfill.equip"); + } + + @Command( + name = "deltree", + desc = "Floating tree remover tool" + ) + @CommandPermissions("worldedit.tool.deltree") + public void deltree(Player player, LocalSession session) throws WorldEditException { + setTool(player, session, new FloatingTreeRemover(), "worldedit.tool.deltree.equip"); + } + + @Command( + name = "farwand", + desc = "Wand at a distance tool" + ) + @CommandPermissions("worldedit.tool.farwand") + public void farwand(Player player, LocalSession session) throws WorldEditException { + setTool(player, session, new DistanceWand(), "worldedit.tool.farwand.equip"); + } + + @Command( + name = "lrbuild", + aliases = { "/lrbuild" }, + desc = "Long-range building tool" + ) + @CommandPermissions("worldedit.tool.lrbuild") + public void longrangebuildtool(Player player, LocalSession session, + @Arg(desc = "Pattern to set on left-click") + Pattern primary, + @Arg(desc = "Pattern to set on right-click") + Pattern secondary) throws WorldEditException { + setTool(player, session, new LongRangeBuildTool(primary, secondary), "worldedit.tool.lrbuild.equip"); + Component primaryName; + Component secondaryName; + if (primary instanceof BlockStateHolder) { + primaryName = ((BlockStateHolder) primary).getBlockType().getRichName(); + } else { + primaryName = TextComponent.of("pattern"); + } + if (secondary instanceof BlockStateHolder) { + secondaryName = ((BlockStateHolder) secondary).getBlockType().getRichName(); + } else { + secondaryName = TextComponent.of("pattern"); + } + player.printInfo(TranslatableComponent.of("worldedit.tool.lrbuild.set", primaryName, secondaryName)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java b/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java new file mode 100644 index 0000000..1bb45f3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java @@ -0,0 +1,141 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.HandSide; +import net.kyori.text.TranslatableComponent; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; + +/** + * Tool commands. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class ToolUtilCommands { + private final WorldEdit we; + + public ToolUtilCommands(WorldEdit we) { + this.we = we; + } + + @Command( + name = "/", + aliases = { "," }, + desc = "Toggle the super pickaxe function" + ) + @CommandPermissions("worldedit.superpickaxe") + public void togglePickaxe(Player player, LocalSession session, + @Arg(desc = "The new super pickaxe state", def = "") + Boolean superPickaxe) { + boolean hasSuperPickAxe = session.hasSuperPickAxe(); + if (superPickaxe != null && superPickaxe == hasSuperPickAxe) { + player.printError(TranslatableComponent.of(superPickaxe ? "worldedit.tool.superpickaxe.enabled.already" : "worldedit.tool.superpickaxe.disabled.already")); + return; + } + if (hasSuperPickAxe) { + session.disableSuperPickAxe(); + player.printInfo(TranslatableComponent.of("worldedit.tool.superpickaxe.disabled")); + } else { + session.enableSuperPickAxe(); + player.printInfo(TranslatableComponent.of("worldedit.tool.superpickaxe.enabled")); + } + + } + + @Command( + name = "mask", + desc = "Set the brush mask" + ) + @CommandPermissions("worldedit.brush.options.mask") + public void mask(Player player, LocalSession session, + @Arg(desc = "The mask to set", def = "") + Mask mask) throws WorldEditException { + session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setMask(mask); + if (mask == null) { + player.printInfo(TranslatableComponent.of("worldedit.tool.mask.disabled")); + } else { + player.printInfo(TranslatableComponent.of("worldedit.tool.mask.set")); + } + } + + @Command( + name = "material", + aliases = { "/material" }, + desc = "Set the brush material" + ) + @CommandPermissions("worldedit.brush.options.material") + public void material(Player player, LocalSession session, + @Arg(desc = "The pattern of blocks to use") + Pattern pattern) throws WorldEditException { + session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setFill(pattern); + player.printInfo(TranslatableComponent.of("worldedit.tool.material.set")); + } + + @Command( + name = "range", + desc = "Set the brush range" + ) + @CommandPermissions("worldedit.brush.options.range") + public void range(Player player, LocalSession session, + @Arg(desc = "The range of the brush") + int range) throws WorldEditException { + session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setRange(range); + player.printInfo(TranslatableComponent.of("worldedit.tool.range.set")); + } + + @Command( + name = "size", + desc = "Set the brush size" + ) + @CommandPermissions("worldedit.brush.options.size") + public void size(Player player, LocalSession session, + @Arg(desc = "The size of the brush") + int size) throws WorldEditException { + we.checkMaxBrushRadius(size); + + session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setSize(size); + player.printInfo(TranslatableComponent.of("worldedit.tool.size.set")); + } + + @Command( + name = "tracemask", + desc = "Set the mask used to stop tool traces" + ) + @CommandPermissions("worldedit.brush.options.tracemask") + public void traceMask(Player player, LocalSession session, + @Arg(desc = "The trace mask to set", def = "") + Mask mask) throws WorldEditException { + session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setTraceMask(mask); + if (mask == null) { + player.printInfo(TranslatableComponent.of("worldedit.tool.tracemask.disabled")); + } else { + player.printInfo(TranslatableComponent.of("worldedit.tool.tracemask.set")); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java new file mode 100644 index 0000000..dbdf124 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -0,0 +1,552 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.command.argument.HeightConverter; +import com.sk89q.worldedit.command.util.*; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.EntityFunction; +import com.sk89q.worldedit.function.mask.BlockTypeMask; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.visitor.EntityVisitor; +import com.sk89q.worldedit.internal.annotation.VertHeight; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.CylinderRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.formatting.component.SubtleFormat; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockTypes; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; + +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.function.Supplier; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; + +/** + * Utility commands. + */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class UtilityCommands { + + private final WorldEdit we; + + public UtilityCommands(WorldEdit we) { + this.we = we; + } + + @Command( + name = "/fill", + desc = "Fill a hole" + ) + @CommandPermissions("worldedit.fill") + @Logging(PLACEMENT) + public int fill(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The blocks to fill with") + Pattern pattern, + @Arg(desc = "The radius to fill in") + double radius, + @Arg(desc = "The depth to fill", def = "1") + int depth) throws WorldEditException { + radius = Math.max(1, radius); + we.checkMaxRadius(radius); + depth = Math.max(1, depth); + + BlockVector3 pos = session.getPlacementPosition(actor); + int affected = editSession.fillXZ(pos, pattern, radius, depth, false); + actor.printInfo(TranslatableComponent.of("worldedit.fill.created", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/fillr", + desc = "Fill a hole recursively" + ) + @CommandPermissions("worldedit.fill.recursive") + @Logging(PLACEMENT) + public int fillr(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The blocks to fill with") + Pattern pattern, + @Arg(desc = "The radius to fill in") + double radius, + @Arg(desc = "The depth to fill", def = "") + Integer depth) throws WorldEditException { + radius = Math.max(1, radius); + we.checkMaxRadius(radius); + depth = depth == null ? Integer.MAX_VALUE : Math.max(1, depth); + we.checkMaxRadius(radius); + + BlockVector3 pos = session.getPlacementPosition(actor); + int affected = editSession.fillXZ(pos, pattern, radius, depth, true); + actor.printInfo(TranslatableComponent.of("worldedit.fillr.created", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "/drain", + desc = "Drain a pool" + ) + @CommandPermissions("worldedit.drain") + @Logging(PLACEMENT) + public int drain(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The radius to drain") + double radius, + @Switch(name = 'w', desc = "Also un-waterlog blocks") + boolean waterlogged) throws WorldEditException { + radius = Math.max(0, radius); + we.checkMaxRadius(radius); + int affected = editSession.drainArea(session.getPlacementPosition(actor), radius, waterlogged); + actor.printInfo(TranslatableComponent.of("worldedit.drain.drained", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "fixlava", + aliases = { "/fixlava" }, + desc = "Fix lava to be stationary" + ) + @CommandPermissions("worldedit.fixlava") + @Logging(PLACEMENT) + public int fixLava(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The radius to fix in") + double radius) throws WorldEditException { + radius = Math.max(0, radius); + we.checkMaxRadius(radius); + int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.LAVA); + actor.printInfo(TranslatableComponent.of("worldedit.fixlava.fixed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "fixwater", + aliases = { "/fixwater" }, + desc = "Fix water to be stationary" + ) + @CommandPermissions("worldedit.fixwater") + @Logging(PLACEMENT) + public int fixWater(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The radius to fix in") + double radius) throws WorldEditException { + radius = Math.max(0, radius); + we.checkMaxRadius(radius); + int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.WATER); + actor.printInfo(TranslatableComponent.of("worldedit.fixwater.fixed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "removeabove", + aliases = { "/removeabove" }, + desc = "Remove blocks above your head." + ) + @CommandPermissions("worldedit.removeabove") + @Logging(PLACEMENT) + public int removeAbove(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The apothem of the square to remove from", def = "1") + int size, + @Arg( + desc = "The maximum height above you to remove from", + def = HeightConverter.DEFAULT_VALUE + ) + @VertHeight + int height) throws WorldEditException { + size = Math.max(1, size); + we.checkMaxRadius(size); + + int affected = editSession.removeAbove(session.getPlacementPosition(actor), size, height); + actor.printInfo(TranslatableComponent.of("worldedit.removeabove.removed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "removebelow", + aliases = { "/removebelow" }, + desc = "Remove blocks below you." + ) + @CommandPermissions("worldedit.removebelow") + @Logging(PLACEMENT) + public int removeBelow(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The apothem of the square to remove from", def = "1") + int size, + @Arg( + desc = "The maximum height below you to remove from", + def = HeightConverter.DEFAULT_VALUE + ) + @VertHeight + int height) throws WorldEditException { + size = Math.max(1, size); + we.checkMaxRadius(size); + + int affected = editSession.removeBelow(session.getPlacementPosition(actor), size, height); + actor.printInfo(TranslatableComponent.of("worldedit.removebelow.removed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "removenear", + aliases = { "/removenear" }, + desc = "Remove blocks near you." + ) + @CommandPermissions("worldedit.removenear") + @Logging(PLACEMENT) + public int removeNear(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The mask of blocks to remove") + Mask mask, + @Arg(desc = "The radius of the square to remove from", def = "50") + int radius) throws WorldEditException { + radius = Math.max(1, radius); + we.checkMaxRadius(radius); + + int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, radius); + actor.printInfo(TranslatableComponent.of("worldedit.removenear.removed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "replacenear", + aliases = { "/replacenear" }, + desc = "Replace nearby blocks" + ) + @CommandPermissions("worldedit.replacenear") + @Logging(PLACEMENT) + public int replaceNear(Actor actor, World world, LocalSession session, EditSession editSession, + @Arg(desc = "The radius of the square to remove in") + int radius, + @Arg(desc = "The mask matching blocks to remove", def = "") + Mask from, + @Arg(desc = "The pattern of blocks to replace with") + Pattern to) throws WorldEditException { + radius = Math.max(1, radius); + we.checkMaxRadius(radius); + + BlockVector3 base = session.getPlacementPosition(actor); + BlockVector3 min = base.subtract(radius, radius, radius); + BlockVector3 max = base.add(radius, radius, radius); + Region region = new CuboidRegion(world, min, max); + + if (from == null) { + from = new ExistingBlockMask(editSession); + } + + int affected = editSession.replaceBlocks(region, from, to); + actor.printInfo(TranslatableComponent.of("worldedit.replacenear.replaced", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "snow", + aliases = { "/snow" }, + desc = "Simulates snow" + ) + @CommandPermissions("worldedit.snow") + @Logging(PLACEMENT) + public int snow(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The radius of the cylinder to snow in", def = "10") + double size, + @Arg( + desc = "The height of the cylinder to snow in", + def = HeightConverter.DEFAULT_VALUE + ) + @VertHeight + int height, + @Switch(name = 's', desc = "Stack snow layers") + boolean stack) throws WorldEditException { + size = Math.max(1, size); + height = Math.max(1, height); + we.checkMaxRadius(size); + + BlockVector3 position = session.getPlacementPosition(actor); + + CylinderRegion region = new CylinderRegion(position, Vector2.at(size, size), position.getBlockY() - height, position.getBlockY() + height); + int affected = editSession.simulateSnow(region, stack); + actor.printInfo(TranslatableComponent.of( + "worldedit.snow.created", TextComponent.of(affected) + )); + return affected; + } + + @Command( + name = "thaw", + aliases = { "/thaw" }, + desc = "Thaws the area" + ) + @CommandPermissions("worldedit.thaw") + @Logging(PLACEMENT) + public int thaw(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The radius of the cylinder to thaw in", def = "10") + double size, + @Arg( + desc = "The height of the cylinder to thaw in", + def = HeightConverter.DEFAULT_VALUE + ) + @VertHeight + int height) throws WorldEditException { + size = Math.max(1, size); + height = Math.max(1, height); + we.checkMaxRadius(size); + + int affected = editSession.thaw(session.getPlacementPosition(actor), size, height); + actor.printInfo(TranslatableComponent.of( + "worldedit.thaw.removed", TextComponent.of(affected) + )); + return affected; + } + + @Command( + name = "green", + aliases = { "/green" }, + desc = "Converts dirt to grass blocks in the area" + ) + @CommandPermissions("worldedit.green") + @Logging(PLACEMENT) + public int green(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The radius of the cylinder to convert in", def = "10") + double size, + @Arg( + desc = "The height of the cylinder to convert in", + def = HeightConverter.DEFAULT_VALUE + ) + @VertHeight + int height, + @Switch(name = 'f', desc = "Also convert coarse dirt") + boolean convertCoarse) throws WorldEditException { + size = Math.max(1, size); + height = Math.max(1, height); + we.checkMaxRadius(size); + final boolean onlyNormalDirt = !convertCoarse; + + final int affected = editSession.green( + session.getPlacementPosition(actor), size, height, onlyNormalDirt + ); + actor.printInfo(TranslatableComponent.of( + "worldedit.green.changed", TextComponent.of(affected) + )); + return affected; + } + + @Command( + name = "extinguish", + aliases = { "/ex", "/ext", "/extinguish", "ex", "ext" }, + desc = "Extinguish nearby fire" + ) + @CommandPermissions("worldedit.extinguish") + @Logging(PLACEMENT) + public int extinguish(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The radius of the square to remove in", def = "") + Integer radius) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40; + int size = radius != null ? Math.max(1, radius) : defaultRadius; + we.checkMaxRadius(size); + + Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE); + int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, size); + actor.printInfo(TranslatableComponent.of("worldedit.extinguish.removed", TextComponent.of(affected))); + return affected; + } + + @Command( + name = "butcher", + desc = "Kill all or nearby mobs" + ) + @CommandPermissions("worldedit.butcher") + @Logging(PLACEMENT) + public int butcher(Actor actor, + @Arg(desc = "Radius to kill mobs in", def = "") + Integer radius, + @Switch(name = 'p', desc = "Also kill pets") + boolean killPets, + @Switch(name = 'n', desc = "Also kill NPCs") + boolean killNpcs, + @Switch(name = 'g', desc = "Also kill golems") + boolean killGolems, + @Switch(name = 'a', desc = "Also kill animals") + boolean killAnimals, + @Switch(name = 'b', desc = "Also kill ambient mobs") + boolean killAmbient, + @Switch(name = 't', desc = "Also kill mobs with name tags") + boolean killWithName, + @Switch(name = 'f', desc = "Also kill all friendly mobs (Applies the flags `-abgnpt`)") + boolean killFriendly, + @Switch(name = 'r', desc = "Also destroy armor stands") + boolean killArmorStands, + @Switch(name = 'w', desc = "Also kill water mobs") + boolean killWater) throws WorldEditException { + LocalConfiguration config = we.getConfiguration(); + + if (radius == null) { + radius = config.butcherDefaultRadius; + } else if (radius < -1) { + actor.printError(TranslatableComponent.of("worldedit.butcher.explain-all")); + return 0; + } else if (radius == -1) { + if (config.butcherMaxRadius != -1) { + radius = config.butcherMaxRadius; + } + } + if (config.butcherMaxRadius != -1) { + radius = Math.min(radius, config.butcherMaxRadius); + } + + CreatureButcher flags = new CreatureButcher(actor); + flags.or(CreatureButcher.Flags.FRIENDLY, killFriendly); // No permission check here. Flags will instead be filtered by the subsequent calls. + flags.or(CreatureButcher.Flags.PETS, killPets, "worldedit.butcher.pets"); + flags.or(CreatureButcher.Flags.NPCS, killNpcs, "worldedit.butcher.npcs"); + flags.or(CreatureButcher.Flags.GOLEMS, killGolems, "worldedit.butcher.golems"); + flags.or(CreatureButcher.Flags.ANIMALS, killAnimals, "worldedit.butcher.animals"); + flags.or(CreatureButcher.Flags.AMBIENT, killAmbient, "worldedit.butcher.ambient"); + flags.or(CreatureButcher.Flags.TAGGED, killWithName, "worldedit.butcher.tagged"); + flags.or(CreatureButcher.Flags.ARMOR_STAND, killArmorStands, "worldedit.butcher.armorstands"); + flags.or(CreatureButcher.Flags.WATER, killWater, "worldedit.butcher.water"); + + int killed = killMatchingEntities(radius, actor, flags::createFunction); + + actor.printInfo(TranslatableComponent.of( + "worldedit.butcher.killed", + TextComponent.of(killed), + TextComponent.of(radius) + )); + + return killed; + } + + @Command( + name = "remove", + aliases = { "rem", "rement" }, + desc = "Remove all entities of a type" + ) + @CommandPermissions("worldedit.remove") + @Logging(PLACEMENT) + public int remove(Actor actor, + @Arg(desc = "The type of entity to remove") + EntityRemover remover, + @Arg(desc = "The radius of the cuboid to remove from") + int radius) throws WorldEditException { + if (radius < -1) { + actor.printError(TranslatableComponent.of("worldedit.remove.explain-all")); + return 0; + } + + int removed = killMatchingEntities(radius, actor, remover::createFunction); + actor.printInfo(TranslatableComponent.of("worldedit.remove.removed", TextComponent.of(removed))); + return removed; + } + + private int killMatchingEntities(Integer radius, Actor actor, Supplier func) throws IncompleteRegionException, + MaxChangedBlocksException { + List visitors = new ArrayList<>(); + + LocalSession session = we.getSessionManager().get(actor); + BlockVector3 center = session.getPlacementPosition(actor); + EditSession editSession = session.createEditSession(actor); + List entities; + if (radius >= 0) { + CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius); + entities = editSession.getEntities(region); + } else { + entities = editSession.getEntities(); + } + visitors.add(new EntityVisitor(entities.iterator(), func.get())); + + int killed = 0; + for (EntityVisitor visitor : visitors) { + Operations.completeLegacy(visitor); + killed += visitor.getAffected(); + } + + session.remember(editSession); + editSession.close(); + return killed; + } + + private DecimalFormat formatForLocale(Locale locale) { + DecimalFormat format = (DecimalFormat) NumberFormat.getInstance(locale); + format.applyPattern("#,##0.#####"); + return format; + } + + @Command( + name = "/calculate", + aliases = { "/calc", "/eval", "/evaluate", "/solve" }, + desc = "Evaluate a mathematical expression" + ) + @CommandPermissions("worldedit.calc") + public void calc(Actor actor, + @Arg(desc = "Expression to evaluate", variable = true) + List input) { + Expression expression; + try { + expression = Expression.compile(String.join(" ", input)); + } catch (ExpressionException e) { + actor.printError(TranslatableComponent.of( + "worldedit.calc.invalid.with-error", + TextComponent.of(String.join(" ", input)), + TextComponent.of(e.getMessage()) + )); + return; + } + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> { + double result = expression.evaluate( + new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout()); + String formatted = Double.isNaN(result) ? "NaN" : formatForLocale(actor.getLocale()).format(result); + return SubtleFormat.wrap(input + " = ").append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE)); + }, (Component) null); + } + + @Command( + name = "/help", + desc = "Displays help for WorldEdit commands" + ) + @CommandPermissions("worldedit.help") + public void help(Actor actor, + @Switch(name = 's', desc = "List sub-commands of the given command, if applicable") + boolean listSubCommands, + @ArgFlag(name = 'p', desc = "The page to retrieve", def = "1") + int page, + @Arg(desc = "The command to retrieve help for", def = "", variable = true) + List command) throws WorldEditException { + PrintCommandHelp.help(command, page, listSubCommands, + we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "//help"); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java b/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java new file mode 100644 index 0000000..00e3e01 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java @@ -0,0 +1,208 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command; + +import com.google.common.io.Files; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.HookMode; +import com.sk89q.worldedit.command.util.PrintCommandHelp; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.PlatformManager; +import com.sk89q.worldedit.util.formatting.component.MessageBox; +import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.paste.ActorCallbackPaste; +import com.sk89q.worldedit.util.report.ConfigReport; +import com.sk89q.worldedit.util.report.ReportList; +import com.sk89q.worldedit.util.report.SystemInfoReport; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.TextStyle; +import java.time.zone.ZoneRulesException; +import java.util.List; + +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class WorldEditCommands { + private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z"); + + private final WorldEdit we; + + public WorldEditCommands(WorldEdit we) { + this.we = we; + } + + @Command( + name = "version", + aliases = { "ver" }, + desc = "Get WorldEdit version" + ) + public void version(Actor actor) { + actor.printInfo(TranslatableComponent.of("worldedit.version.version", TextComponent.of(WorldEdit.getVersion()))); + actor.printInfo(TextComponent.of("https://github.com/EngineHub/WorldEdit/")); + + PlatformManager pm = we.getPlatformManager(); + + TextComponentProducer producer = new TextComponentProducer(); + for (Platform platform : pm.getPlatforms()) { + producer.append( + TextComponent.of("* ", TextColor.GRAY) + .append(TextComponent.of(platform.getPlatformName())) + .append(TextComponent.of("(" + platform.getPlatformVersion() + ")")) + ).newline(); + } + actor.print(new MessageBox("Platforms", producer, TextColor.GRAY).create()); + + producer.reset(); + for (Capability capability : Capability.values()) { + Platform platform = pm.queryCapability(capability); + producer.append( + TextComponent.of(capability.name(), TextColor.GRAY) + .append(TextComponent.of(": ") + .append(TextComponent.of(platform != null ? platform.getPlatformName() : "NONE"))) + ).newline(); + } + actor.print(new MessageBox("Capabilities", producer, TextColor.GRAY).create()); + } + + @Command( + name = "reload", + desc = "Reload configuration" + ) + @CommandPermissions("worldedit.reload") + public void reload(Actor actor) { + we.getPlatformManager().queryCapability(Capability.CONFIGURATION).reload(); + we.getEventBus().post(new ConfigurationLoadEvent(we.getPlatformManager().queryCapability(Capability.CONFIGURATION).getConfiguration())); + actor.printInfo(TranslatableComponent.of("worldedit.reload.config")); + } + + @Command( + name = "report", + desc = "Writes a report on WorldEdit" + ) + @CommandPermissions("worldedit.report") + public void report(Actor actor, + @Switch(name = 'p', desc = "Pastebins the report") + boolean pastebin) throws WorldEditException { + ReportList report = new ReportList("Report"); + report.add(new SystemInfoReport()); + report.add(new ConfigReport()); + String result = report.toString(); + + try { + File dest = new File(we.getConfiguration().getWorkingDirectory(), "report.txt"); + Files.write(result, dest, StandardCharsets.UTF_8); + actor.printInfo(TranslatableComponent.of("worldedit.report.written", TextComponent.of(dest.getAbsolutePath()))); + } catch (IOException e) { + actor.printError(TranslatableComponent.of("worldedit.report.error", TextComponent.of(e.getMessage()))); + } + + if (pastebin) { + actor.checkPermission("worldedit.report.pastebin"); + ActorCallbackPaste.pastebin(we.getSupervisor(), actor, result, TranslatableComponent.builder("worldedit.report.callback")); + } + } + + @Command( + name = "trace", + desc = "Toggles trace hook" + ) + void trace(Actor actor, LocalSession session, + @Arg(desc = "The mode to set the trace hook to", def = "") + HookMode hookMode) { + boolean previousMode = session.isTracingActions(); + boolean newMode; + if (hookMode != null) { + newMode = hookMode == HookMode.ACTIVE; + if (newMode == previousMode) { + actor.printError(TranslatableComponent.of(previousMode ? "worldedit.trace.active.already" : "worldedit.trace.inactive.already")); + return; + } + } else { + newMode = !previousMode; + } + session.setTracingActions(newMode); + actor.printInfo(TranslatableComponent.of(newMode ? "worldedit.trace.active" : "worldedit.trace.inactive")); + } + + @Command( + name = "cui", + desc = "Complete CUI handshake (internal usage)" + ) + public void cui(Player player, LocalSession session) { + session.setCUISupport(true); + session.dispatchCUISetup(player); + } + + @Command( + name = "tz", + desc = "Set your timezone for snapshots" + ) + public void tz(Actor actor, LocalSession session, + @Arg(desc = "The timezone to set") + String timezone) { + try { + ZoneId tz = ZoneId.of(timezone); + session.setTimezone(tz); + actor.printInfo(TranslatableComponent.of("worldedit.timezone.set", TextComponent.of(tz.getDisplayName( + TextStyle.FULL, actor.getLocale() + )))); + actor.printInfo(TranslatableComponent.of("worldedit.timezone.current", + TextComponent.of(dateFormat.withLocale(actor.getLocale()).format(ZonedDateTime.now(tz))))); + } catch (ZoneRulesException e) { + actor.printError(TranslatableComponent.of("worldedit.timezone.invalid")); + } + } + + @Command( + name = "help", + desc = "Displays help for WorldEdit commands" + ) + @CommandPermissions("worldedit.help") + public void help(Actor actor, + @Switch(name = 's', desc = "List sub-commands of the given command, if applicable") + boolean listSubCommands, + @ArgFlag(name = 'p', desc = "The page to retrieve", def = "1") + int page, + @Arg(desc = "The command to retrieve help for", def = "", variable = true) + List command) throws WorldEditException { + PrintCommandHelp.help(command, page, listSubCommands, + we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "/worldedit help"); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/AbstractDirectionConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/AbstractDirectionConverter.java new file mode 100644 index 0000000..9c8166a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/AbstractDirectionConverter.java @@ -0,0 +1,121 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.auto.value.AutoAnnotation; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.UnknownDirectionException; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.annotation.MultiDirection; +import com.sk89q.worldedit.internal.annotation.OptionalArg; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import javax.annotation.Nullable; + +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + +public abstract class AbstractDirectionConverter implements ArgumentConverter { + + @AutoAnnotation + private static Direction direction(boolean includeDiagonals) { + return new AutoAnnotation_AbstractDirectionConverter_direction(includeDiagonals); + } + + @AutoAnnotation + private static MultiDirection multiDirection(boolean includeDiagonals) { + return new AutoAnnotation_AbstractDirectionConverter_multiDirection(includeDiagonals); + } + + protected static void register(CommandManager commandManager, AbstractDirectionConverter converter, + Class keyClass, boolean includeDiagonals) { + commandManager.registerConverter( + Key.of(keyClass, direction(includeDiagonals)), + converter + ); + commandManager.registerConverter( + Key.of(keyClass, multiDirection(includeDiagonals)), + CommaSeparatedValuesConverter.wrap(converter) + ); + } + + private static final ImmutableSet ORTHOGONAL = ImmutableSet.of( + "north", "south", "east", "west", "up", "down" + ); + private static final ImmutableSet RELATIVE = ImmutableSet.of( + "me", "forward", "back", "left", "right" + ); + private static final ImmutableSet DIAGONAL = ImmutableSet.of( + "northeast", "northwest", "southeast", "southwest" + ); + + private final WorldEdit worldEdit; + private final boolean includeDiagonals; + private final ImmutableList suggestions; + + protected AbstractDirectionConverter(WorldEdit worldEdit, boolean includeDiagonals) { + this.worldEdit = worldEdit; + this.includeDiagonals = includeDiagonals; + suggestions = ImmutableList.builder() + .addAll(ORTHOGONAL) + .addAll(RELATIVE) + .addAll(includeDiagonals ? DIAGONAL : ImmutableList.of()) + .build(); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + Player player = context.injectedValue(Key.of(Player.class, OptionalArg.class)) + .orElse(null); + try { + return SuccessfulConversion.fromSingle(convertDirection(argument, player, includeDiagonals)); + } catch (Exception e) { + return FailedConversion.from(e); + } + } + + protected abstract D convertDirection(String argument, @Nullable Player player, boolean includeDiagonals) throws UnknownDirectionException; + + @Override + public Component describeAcceptableArguments() { + return TextComponent.of("`me` to use facing direction, or any " + + (includeDiagonals ? "direction" : "non-diagonal direction")); + } + + @Override + public List getSuggestions(String input, InjectedValueAccess context) { + return limitByPrefix(suggestions.stream(), input); + } + + protected WorldEdit getWorldEdit() { + return worldEdit; + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java b/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java new file mode 100644 index 0000000..b4ebbc7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java @@ -0,0 +1,32 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + + +import org.enginehub.piston.inject.InjectedValueAccess; + +/** + * Key-interface for {@link InjectedValueAccess} for the String arguments. + */ +public interface Arguments { + + String get(); + +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/AutoAnnotation_AbstractDirectionConverter_direction.java b/src/main/java/com/sk89q/worldedit/command/argument/AutoAnnotation_AbstractDirectionConverter_direction.java new file mode 100644 index 0000000..40a2622 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/AutoAnnotation_AbstractDirectionConverter_direction.java @@ -0,0 +1,54 @@ +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.internal.annotation.Direction; +import java.io.Serializable; + +final class AutoAnnotation_AbstractDirectionConverter_direction implements Direction, Serializable { + private static final long serialVersionUID = 231310279470082624L; + + private final boolean includeDiagonals; + + AutoAnnotation_AbstractDirectionConverter_direction( + boolean includeDiagonals) { + this.includeDiagonals = includeDiagonals; + } + + @Override + public Class annotationType() { + return Direction.class; + } + + @Override + public boolean includeDiagonals() { + return includeDiagonals; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("@com.sk89q.worldedit.internal.annotation.Direction("); + sb.append("includeDiagonals="); + sb.append(includeDiagonals); + return sb.append(')').toString(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Direction) { + Direction that = (Direction) o; + return (includeDiagonals == that.includeDiagonals()); + } + return false; + } + + @Override + public int hashCode() { + return + + (1498019818 ^ (includeDiagonals ? 1231 : 1237)) + // 1498019818 is 127 * "includeDiagonals".hashCode() + ; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/AutoAnnotation_AbstractDirectionConverter_multiDirection.java b/src/main/java/com/sk89q/worldedit/command/argument/AutoAnnotation_AbstractDirectionConverter_multiDirection.java new file mode 100644 index 0000000..e6dc389 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/AutoAnnotation_AbstractDirectionConverter_multiDirection.java @@ -0,0 +1,54 @@ +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.internal.annotation.MultiDirection; +import java.io.Serializable; + +final class AutoAnnotation_AbstractDirectionConverter_multiDirection implements MultiDirection, Serializable { + private static final long serialVersionUID = 231310279470082624L; + + private final boolean includeDiagonals; + + AutoAnnotation_AbstractDirectionConverter_multiDirection( + boolean includeDiagonals) { + this.includeDiagonals = includeDiagonals; + } + + @Override + public Class annotationType() { + return MultiDirection.class; + } + + @Override + public boolean includeDiagonals() { + return includeDiagonals; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("@com.sk89q.worldedit.internal.annotation.MultiDirection("); + sb.append("includeDiagonals="); + sb.append(includeDiagonals); + return sb.append(')').toString(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof MultiDirection) { + MultiDirection that = (MultiDirection) o; + return (includeDiagonals == that.includeDiagonals()); + } + return false; + } + + @Override + public int hashCode() { + return + + (1498019818 ^ (includeDiagonals ? 1231 : 1237)) + // 1498019818 is 127 * "includeDiagonals".hashCode() + ; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java new file mode 100644 index 0000000..0ea15a2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.ImmutableSetMultimap; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.MultiKeyConverter; +import org.enginehub.piston.inject.Key; + +public class BooleanConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(Boolean.class), + MultiKeyConverter.builder( + ImmutableSetMultimap.builder() + .putAll(false, "off", "f", "false", "n", "no") + .putAll(true, "on", "t", "true", "y", "yes") + .build() + ) + .errorMessage(arg -> "Not a boolean value: " + arg) + .build() + ); + } + + private BooleanConverter() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/Chunk3dVectorConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/Chunk3dVectorConverter.java new file mode 100644 index 0000000..9894753 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/Chunk3dVectorConverter.java @@ -0,0 +1,96 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Range; +import com.google.common.reflect.TypeToken; +import com.sk89q.worldedit.internal.annotation.Chunk3d; +import com.sk89q.worldedit.math.BlockVector3; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ArgumentConverters; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import java.util.function.Function; + +public class Chunk3dVectorConverter implements ArgumentConverter { + public static void register(CommandManager commandManager) { + CommaSeparatedValuesConverter intConverter = CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(int.class))); + commandManager.registerConverter(Key.of(BlockVector3.class, Chunk3d.class), + new Chunk3dVectorConverter<>( + intConverter, + Range.closed(2, 3), + cmps -> { + switch (cmps.size()) { + case 2: + return BlockVector3.at(cmps.get(0), 0, cmps.get(1)); + case 3: + return BlockVector3.at(cmps.get(0), cmps.get(1), cmps.get(2)); + default: + break; + } + throw new AssertionError("Expected 2 or 3 components"); + }, + "block vector in the form x,z or x,y,z" + )); + } + + private final ArgumentConverter componentConverter; + private final Range componentCount; + private final Function, T> vectorConstructor; + private final String acceptableArguments; + + private Chunk3dVectorConverter(ArgumentConverter componentConverter, + Range componentCount, + Function, T> vectorConstructor, + String acceptableArguments) { + this.componentConverter = componentConverter; + this.componentCount = componentCount; + this.vectorConstructor = vectorConstructor; + this.acceptableArguments = acceptableArguments; + } + + @Override + public Component describeAcceptableArguments() { + return TextComponent.of("any " + acceptableArguments); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + ConversionResult components = componentConverter.convert(argument, context); + if (!components.isSuccessful()) { + return components.failureAsAny(); + } + if (!componentCount.contains(components.get().size())) { + return FailedConversion.from(new IllegalArgumentException( + "Must have " + componentCount + " vector components")); + } + T vector = vectorConstructor.apply(ImmutableList.copyOf(components.get())); + return SuccessfulConversion.fromSingle(vector); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java new file mode 100644 index 0000000..3344f25 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static net.kyori.text.TextComponent.space; + +public class CommaSeparatedValuesConverter implements ArgumentConverter { + + public static CommaSeparatedValuesConverter wrap(ArgumentConverter delegate) { + return wrapAndLimit(delegate, -1); + } + + public static CommaSeparatedValuesConverter wrapAndLimit(ArgumentConverter delegate, int maximum) { + return new CommaSeparatedValuesConverter<>(delegate, maximum); + } + + private static final Splitter COMMA = Splitter.on(','); + + private final ArgumentConverter delegate; + private final int maximum; + + private CommaSeparatedValuesConverter(ArgumentConverter delegate, int maximum) { + checkArgument(maximum == -1 || maximum > 1, + "Maximum must be bigger than 1, or exactly -1"); + this.delegate = delegate; + this.maximum = maximum; + } + + @Override + public Component describeAcceptableArguments() { + TextComponent.Builder result = TextComponent.builder(""); + if (maximum > -1) { + result.append(TextComponent.of("up to ")) + .append(TextComponent.of(maximum)) + .append(space()); + } + result.append(TextComponent.of("comma separated values of: ")) + .append(delegate.describeAcceptableArguments()); + return result.build(); + } + + @Override + public List getSuggestions(String input, InjectedValueAccess context) { + String lastInput = Iterables.getLast(COMMA.split(input), ""); + assert lastInput != null; + return delegate.getSuggestions(lastInput, context); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + ImmutableList.Builder result = ImmutableList.builder(); + for (String input : COMMA.split(argument)) { + ConversionResult temp = delegate.convert(input, context); + if (!temp.isSuccessful()) { + return temp; + } + result.addAll(temp.get()); + } + return SuccessfulConversion.from(result.build()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java new file mode 100644 index 0000000..594d825 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java @@ -0,0 +1,54 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.UnknownDirectionException; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import org.enginehub.piston.CommandManager; + +import javax.annotation.Nullable; +import java.util.Optional; + +public final class DirectionConverter extends AbstractDirectionConverter { + + private DirectionConverter(WorldEdit worldEdit, boolean includeDiagonals) { + super(worldEdit, includeDiagonals); + } + + public static void register(WorldEdit worldEdit, CommandManager commandManager) { + for (boolean includeDiagonals : new boolean[] { false, true }) { + DirectionConverter directionConverter = new DirectionConverter(worldEdit, includeDiagonals); + register(commandManager, directionConverter, Direction.class, includeDiagonals); + } + } + + @Override + protected Direction convertDirection(String argument, @Nullable Player player, boolean includeDiagonals) throws UnknownDirectionException { + final BlockVector3 vec = includeDiagonals + ? getWorldEdit().getDiagonalDirection(player, argument) + : getWorldEdit().getDirection(player, argument); + return Optional.ofNullable(Direction.findClosest(vec.toVector3(), Direction.Flag.ALL)) + .orElseThrow(() -> new UnknownDirectionException(argument)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/DirectionVectorConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/DirectionVectorConverter.java new file mode 100644 index 0000000..4d01d14 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/DirectionVectorConverter.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.UnknownDirectionException; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.math.BlockVector3; +import org.enginehub.piston.CommandManager; + +import javax.annotation.Nullable; + +public final class DirectionVectorConverter extends AbstractDirectionConverter { + + public DirectionVectorConverter(WorldEdit worldEdit, boolean includeDiagonals) { + super(worldEdit, includeDiagonals); + } + + public static void register(WorldEdit worldEdit, CommandManager commandManager) { + for (boolean includeDiagonals : new boolean[] { false, true }) { + DirectionVectorConverter directionConverter = new DirectionVectorConverter(worldEdit, includeDiagonals); + register(commandManager, directionConverter, BlockVector3.class, includeDiagonals); + } + } + + @Override + protected BlockVector3 convertDirection(String argument, @Nullable Player player, boolean includeDiagonals) throws UnknownDirectionException { + return includeDiagonals + ? getWorldEdit().getDiagonalDirection(player, argument) + : getWorldEdit().getDirection(player, argument); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java new file mode 100644 index 0000000..c60e196 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java @@ -0,0 +1,70 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.command.util.EntityRemover; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; + +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + +public class EntityRemoverConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(EntityRemover.class), new EntityRemoverConverter()); + } + + private final List suggestions + = ImmutableList.of("projectiles", "items", "paintings", "itemframes", "boats", "minecarts", "tnt", "xp", "all"); + + private EntityRemoverConverter() { + } + + @Override + public Component describeAcceptableArguments() { + return TextComponent.of( + "projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all" + ); + } + + @Override + public List getSuggestions(String input, InjectedValueAccess context) { + return limitByPrefix(suggestions.stream(), input); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + try { + return SuccessfulConversion.fromSingle(EntityRemover.fromString(argument)); + } catch (Exception e) { + return FailedConversion.from(e); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java new file mode 100644 index 0000000..75995dc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java @@ -0,0 +1,84 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.command.util.HookMode; +import com.sk89q.worldedit.extent.TracingExtent; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.TreeGenerator; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.MultiKeyConverter; +import org.enginehub.piston.inject.Key; + +import javax.annotation.Nullable; +import java.util.EnumSet; +import java.util.Locale; +import java.util.Set; +import java.util.function.Function; + +public final class EnumConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(SelectorChoice.class), + basic(SelectorChoice.class)); + commandManager.registerConverter(Key.of(TreeGenerator.TreeType.class), + full(TreeGenerator.TreeType.class, + t -> ImmutableSet.copyOf(t.lookupKeys), + null)); + commandManager.registerConverter(Key.of(EditSession.ReorderMode.class), + full(EditSession.ReorderMode.class, + r -> ImmutableSet.of(r.getDisplayName()), + null)); + commandManager.registerConverter(Key.of(SideEffect.State.class), + MultiKeyConverter.from( + EnumSet.of(SideEffect.State.OFF, SideEffect.State.ON), + r -> ImmutableSet.of(r.name().toLowerCase(Locale.US)), + null)); + commandManager.registerConverter(Key.of(HookMode.class), + basic(HookMode.class)); + commandManager.registerConverter(Key.of(TracingExtent.Action.class), + basic(TracingExtent.Action.class)); + } + + private static > ArgumentConverter basic(Class enumClass) { + return full(enumClass, e -> ImmutableSet.of(e.name().toLowerCase(Locale.ROOT)), null); + } + + private static > ArgumentConverter basic(Class enumClass, @Nullable E unknownValue) { + return full(enumClass, e -> ImmutableSet.of(e.name().toLowerCase(Locale.ROOT)), unknownValue); + } + + private static > ArgumentConverter full(Class enumClass, + Function> lookupKeys, + @Nullable E unknownValue) { + return MultiKeyConverter.from( + EnumSet.allOf(enumClass), + lookupKeys, + unknownValue + ); + } + + private EnumConverter() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java new file mode 100644 index 0000000..a763db7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -0,0 +1,142 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.EmptyClipboardException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.transform.BlockTransformExtent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.ClipboardMask; +import com.sk89q.worldedit.internal.registry.AbstractFactory; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.session.request.RequestExtent; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import com.sk89q.worldedit.world.World; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +public class FactoryConverter implements ArgumentConverter { + + public static void register(WorldEdit worldEdit, CommandManager commandManager) { + commandManager.registerConverter(Key.of(Pattern.class), + new FactoryConverter<>(worldEdit, WorldEdit::getPatternFactory, "pattern", null)); + commandManager.registerConverter(Key.of(Mask.class), + new FactoryConverter<>(worldEdit, WorldEdit::getMaskFactory, "mask", null)); + commandManager.registerConverter(Key.of(BaseItem.class), + new FactoryConverter<>(worldEdit, WorldEdit::getItemFactory, "item", null)); + + commandManager.registerConverter(Key.of(Mask.class, ClipboardMask.class), + new FactoryConverter<>(worldEdit, WorldEdit::getMaskFactory, "mask", + context -> { + try { + ClipboardHolder holder = context.getSession().getClipboard(); + Transform transform = holder.getTransform(); + Extent target; + if (transform.isIdentity()) { + target = holder.getClipboard(); + } else { + target = new BlockTransformExtent(holder.getClipboard(), transform); + } + context.setExtent(target); + } catch (EmptyClipboardException e) { + throw new IllegalStateException(e); + } + })); + } + + private final WorldEdit worldEdit; + private final Function> factoryExtractor; + private final String description; + @Nullable private final Consumer contextTweaker; + + private FactoryConverter(WorldEdit worldEdit, + Function> factoryExtractor, + String description, + @Nullable Consumer contextTweaker) { + this.worldEdit = worldEdit; + this.factoryExtractor = factoryExtractor; + this.description = description; + this.contextTweaker = contextTweaker; + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + Actor actor = context.injectedValue(Key.of(Actor.class)) + .orElseThrow(() -> new IllegalStateException("No actor")); + LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); + + ParserContext parserContext = new ParserContext(); + parserContext.setActor(actor); + if (actor instanceof Locatable) { + Extent extent = ((Locatable) actor).getExtent(); + if (extent instanceof World) { + parserContext.setWorld((World) extent); + } + parserContext.setExtent(new RequestExtent()); + } else if (session.hasWorldOverride()) { + parserContext.setWorld(session.getWorldOverride()); + parserContext.setExtent(new RequestExtent()); + } + parserContext.setSession(session); + parserContext.setRestricted(true); + + if (contextTweaker != null) { + contextTweaker.accept(parserContext); + } + + try { + return SuccessfulConversion.fromSingle( + factoryExtractor.apply(worldEdit).parseFromInput(argument, parserContext) + ); + } catch (InputParseException e) { + return FailedConversion.from(e); + } + } + + @Override + public List getSuggestions(String input, InjectedValueAccess context) { + return factoryExtractor.apply(worldEdit).getSuggestions(input); + } + + @Override + public Component describeAcceptableArguments() { + return TextComponent.of("any " + description); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/HeightConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/HeightConverter.java new file mode 100644 index 0000000..6d04283 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/HeightConverter.java @@ -0,0 +1,74 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.reflect.TypeToken; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.internal.annotation.VertHeight; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ArgumentConverters; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +/** + * Converter for handling default heights as the + * {@linkplain LocalConfiguration#defaultVerticalHeight currently configured + * height}. + */ +public class HeightConverter implements ArgumentConverter { + + /** + * The value that converts to the default vertical height. + */ + public static final String DEFAULT_VALUE = "default-vertical-height"; + + private static final ArgumentConverter INT_CONVERTER = + ArgumentConverters.get(TypeToken.of(int.class)); + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(int.class, VertHeight.class), + new HeightConverter() + ); + } + + private HeightConverter() { + } + + @Override + public Component describeAcceptableArguments() { + return TextComponent.of("Any integer"); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + if (DEFAULT_VALUE.equals(argument)) { + return SuccessfulConversion.fromSingle( + WorldEdit.getInstance().getConfiguration().defaultVerticalHeight + ); + } + return INT_CONVERTER.convert(argument, context); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/OffsetConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/OffsetConverter.java new file mode 100644 index 0000000..5b9edd9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/OffsetConverter.java @@ -0,0 +1,139 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.internal.annotation.Offset; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MathUtils; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import java.util.stream.Collectors; + +public class OffsetConverter implements ArgumentConverter { + + public static void register(WorldEdit worldEdit, CommandManager commandManager) { + commandManager.registerConverter( + Key.of(BlockVector3.class, Offset.class), + new OffsetConverter(worldEdit) + ); + } + + private final DirectionVectorConverter directionVectorConverter; + private final VectorConverter vectorConverter = + VectorConverter.BLOCK_VECTOR_3_CONVERTER; + + private OffsetConverter(WorldEdit worldEdit) { + directionVectorConverter = new DirectionVectorConverter(worldEdit, true); + } + + @Override + public Component describeAcceptableArguments() { + return TextComponent.builder() + .append(directionVectorConverter.describeAcceptableArguments()) + .append(", or ") + .append(vectorConverter.describeAcceptableArguments()) + .build(); + } + + @Override + public List getSuggestions(String input, InjectedValueAccess context) { + if (input.startsWith("^") && context.injectedValue(Key.of(Actor.class)) + .filter(actor -> actor instanceof Locatable).isPresent()) { + return vectorConverter.getSuggestions(input.substring(1), context).stream() + .map(s -> "^" + s) + .collect(Collectors.toList()); + } + return ImmutableList.copyOf(Iterables.concat( + directionVectorConverter.getSuggestions(input, context), + vectorConverter.getSuggestions(input, context) + )); + } + + private BlockVector3 rotateToRelative(Location location, BlockVector3 relativeOffset) { + float pitch = location.getPitch(); + float yaw = location.getYaw(); + + // This math was borrowed from the MC codebase, with some changes made for accuracy + double f = MathUtils.dCos(yaw + 90.0); + double g = MathUtils.dSin(yaw + 90.0); + double j = MathUtils.dCos(-pitch + 90.0); + double k = MathUtils.dSin(-pitch + 90.0); + + Vector3 m1 = location.getDirection(); + Vector3 m2 = Vector3.at(f * j, k, g * j); + Vector3 m3 = m1.cross(m2).multiply(-1.0D); + + // Create an affine transform of the columns (col4 is empty due to no translation) + AffineTransform transform = new AffineTransform( + m1.getX(), m2.getX(), m3.getX(), 0, + m1.getY(), m2.getY(), m3.getY(), 0, + m1.getZ(), m2.getZ(), m3.getZ(), 0 + ); + + return transform + .apply(relativeOffset.toVector3()) + // This *MUST* be rounded before converting to block points + .round().toBlockPoint(); + } + + @Override + public ConversionResult convert(String input, InjectedValueAccess context) { + if (input.startsWith("^")) { + try { + // Looking at a relative vector. + Actor actor = context.injectedValue(Key.of(Actor.class)) + .orElseThrow(() -> new IllegalStateException("An actor is required to use relative offsets")); + + if (!(actor instanceof Locatable)) { + throw new IllegalStateException("Only a locatable actor may use relative offsets"); + } + + Location location = ((Locatable) actor).getLocation(); + + return vectorConverter.convert(input.substring(1), context).map(blockVector3s -> + blockVector3s.stream() + .map(vector -> rotateToRelative(location, vector)) + .collect(Collectors.toList()) + ); + } catch (IllegalStateException e) { + return FailedConversion.from(e); + } + } else { + return directionVectorConverter.convert(input, context) + .orElse(vectorConverter.convert(input, context)); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java new file mode 100644 index 0000000..160c1c1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.ImmutableSetMultimap; +import com.sk89q.worldedit.regions.factory.CuboidRegionFactory; +import com.sk89q.worldedit.regions.factory.CylinderRegionFactory; +import com.sk89q.worldedit.regions.factory.RegionFactory; +import com.sk89q.worldedit.regions.factory.SphereRegionFactory; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.MultiKeyConverter; +import org.enginehub.piston.inject.Key; + +public class RegionFactoryConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(RegionFactory.class), + MultiKeyConverter.builder( + ImmutableSetMultimap.builder() + .put(new CuboidRegionFactory(), "cuboid") + .put(new SphereRegionFactory(), "sphere") + .putAll(new CylinderRegionFactory(1), "cyl", "cylinder") + .build() + ) + .errorMessage(arg -> "Not a known region type: " + arg) + .build() + ); + } + + private RegionFactoryConverter() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java new file mode 100644 index 0000000..3f634d4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java @@ -0,0 +1,113 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.Registry; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.fluid.FluidCategory; +import com.sk89q.worldedit.world.fluid.FluidType; +import com.sk89q.worldedit.world.gamemode.GameMode; +import com.sk89q.worldedit.world.item.ItemCategory; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.weather.WeatherType; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +public final class RegistryConverter implements ArgumentConverter { + + @SuppressWarnings("unchecked") + public static void register(CommandManager commandManager) { + ImmutableList.of( + BlockType.class, + BlockCategory.class, + ItemType.class, + ItemCategory.class, + BiomeType.class, + EntityType.class, + FluidType.class, + FluidCategory.class, + GameMode.class, + WeatherType.class + ) + .stream() + .map(c -> (Class) c) + .forEach(registryType -> + commandManager.registerConverter(Key.of(registryType), from(registryType)) + ); + } + + @SuppressWarnings("unchecked") + private static RegistryConverter from(Class registryType) { + try { + Field registryField = registryType.getDeclaredField("REGISTRY"); + Registry registry = (Registry) registryField.get(null); + return new RegistryConverter<>(registry); + } catch (NoSuchFieldException e) { + throw new IllegalArgumentException("Not a registry-backed type: " + registryType.getName()); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Registry field inaccessible on " + registryType.getName()); + } + } + + private final Registry registry; + private final TextComponent choices; + + private RegistryConverter(Registry registry) { + this.registry = registry; + this.choices = TextComponent.of("any " + registry.getName()); + } + + @Override + public Component describeAcceptableArguments() { + return this.choices; + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess injectedValueAccess) { + V result = registry.get(argument.toLowerCase(Locale.ROOT)); + return result == null + ? FailedConversion.from(new IllegalArgumentException( + "Not a valid " + registry.getName() + ": " + argument)) + : SuccessfulConversion.fromSingle(result); + } + + @Override + public List getSuggestions(String input, InjectedValueAccess context) { + return SuggestionHelper.getRegistrySuggestions(registry, input).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java b/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java new file mode 100644 index 0000000..36eabc1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java @@ -0,0 +1,33 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +public enum SelectorChoice { + CUBOID, + EXTEND, + POLY, + ELLIPSOID, + SPHERE, + CYL, + CONVEX, + HULL, + POLYHEDRON, + LIST +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/SideEffectConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/SideEffectConverter.java new file mode 100644 index 0000000..5394068 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/SideEffectConverter.java @@ -0,0 +1,73 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.util.SideEffect; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + +public class SideEffectConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(SideEffect.class), new SideEffectConverter()); + } + + private final TextComponent choices = TextComponent.of("any side effect"); + + private SideEffectConverter() { + } + + private Collection getSideEffects() { + return WorldEdit.getInstance().getPlatformManager().getSupportedSideEffects(); + } + + @Override + public Component describeAcceptableArguments() { + return choices; + } + + @Override + public List getSuggestions(String input, InjectedValueAccess context) { + return limitByPrefix(getSideEffects().stream().map(sideEffect -> sideEffect.name().toLowerCase(Locale.US)), input); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + try { + return SuccessfulConversion.fromSingle(SideEffect.valueOf(argument.toUpperCase(Locale.US))); + } catch (Exception e) { + return FailedConversion.from(e); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java new file mode 100644 index 0000000..38e0ccd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java @@ -0,0 +1,114 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.math.Vector3; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ArgumentConverters; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import java.util.function.Function; + +public class VectorConverter implements ArgumentConverter { + + private static final CommaSeparatedValuesConverter INT_CONVERTER = + CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(int.class))); + + public static final VectorConverter BLOCK_VECTOR_3_CONVERTER = new VectorConverter<>( + INT_CONVERTER, + 3, + cmps -> BlockVector3.at(cmps.get(0), cmps.get(1), cmps.get(2)), + "block vector in the form x,y,z" + ); + + public static void register(CommandManager commandManager) { + CommaSeparatedValuesConverter doubleConverter = CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(double.class))); + commandManager.registerConverter(Key.of(BlockVector2.class), + new VectorConverter<>( + INT_CONVERTER, + 2, + cmps -> BlockVector2.at(cmps.get(0), cmps.get(1)), + "block vector in the form x,z" + )); + commandManager.registerConverter(Key.of(Vector2.class), + new VectorConverter<>( + doubleConverter, + 2, + cmps -> Vector2.at(cmps.get(0), cmps.get(1)), + "vector in the form x,z" + )); + commandManager.registerConverter(Key.of(BlockVector3.class), BLOCK_VECTOR_3_CONVERTER); + commandManager.registerConverter(Key.of(Vector3.class), + new VectorConverter<>( + doubleConverter, + 3, + cmps -> Vector3.at(cmps.get(0), cmps.get(1), cmps.get(2)), + "vector in the form x,y,z" + )); + } + + private final ArgumentConverter componentConverter; + private final int componentCount; + private final Function, T> vectorConstructor; + private final String acceptableArguments; + + + private VectorConverter(ArgumentConverter componentConverter, + int componentCount, + Function, T> vectorConstructor, + String acceptableArguments) { + this.componentConverter = componentConverter; + this.componentCount = componentCount; + this.vectorConstructor = vectorConstructor; + this.acceptableArguments = acceptableArguments; + } + + @Override + public Component describeAcceptableArguments() { + return TextComponent.of("any " + acceptableArguments); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + ConversionResult components = componentConverter.convert(argument, context); + if (!components.isSuccessful()) { + return components.failureAsAny(); + } + if (components.get().size() != componentCount) { + return FailedConversion.from(new IllegalArgumentException( + "Must have exactly " + componentCount + " vector components")); + } + T vector = vectorConstructor.apply(ImmutableList.copyOf(components.get())); + return SuccessfulConversion.fromSingle(vector); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java new file mode 100644 index 0000000..f3d9002 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import com.sk89q.worldedit.world.World; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class WorldConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(World.class), + new WorldConverter() + ); + } + + private final TextComponent choices; + + private WorldConverter() { + this.choices = TextComponent.of("any world"); + } + + @Override + public Component describeAcceptableArguments() { + return this.choices; + } + + private Stream getWorlds() { + return WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getWorlds().stream(); + } + + @Override + public List getSuggestions(String input, InjectedValueAccess context) { + return getWorlds() + .map(World::getId) + .filter(world -> world.startsWith(input)) + .collect(Collectors.toList()); + } + + @Override + public ConversionResult convert(String s, InjectedValueAccess injectedValueAccess) { + World result = getWorlds() + .filter(world -> world.getId().equals(s)) + .findAny().orElse(null); + return result == null + ? FailedConversion.from(new IllegalArgumentException( + "Not a valid world: " + s)) + : SuccessfulConversion.fromSingle(result); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java b/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java new file mode 100644 index 0000000..4cb8df6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.LocalSession; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Calendar; + +public class ZonedDateTimeConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(ZonedDateTime.class), new ZonedDateTimeConverter()); + } + + private ZonedDateTimeConverter() { + } + + @Override + public Component describeAcceptableArguments() { + return TextComponent.of("any date"); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + LocalSession session = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("Need a local session")); + Calendar date = session.detectDate(argument); + if (date == null) { + return FailedConversion.from(new IllegalArgumentException("Not a date: " + argument)); + } + return SuccessfulConversion.fromSingle(date.toInstant().atZone(ZoneOffset.UTC)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/argument/package-info.java b/src/main/java/com/sk89q/worldedit/command/argument/package-info.java new file mode 100644 index 0000000..423e6d2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/argument/package-info.java @@ -0,0 +1,21 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +@org.enginehub.piston.util.NonnullByDefault +package com.sk89q.worldedit.command.argument; diff --git a/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java b/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java new file mode 100644 index 0000000..ef15981 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java @@ -0,0 +1,54 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.factory; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.ItemUseFunction; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.World; + +public final class ItemUseFactory implements Contextual { + private final BaseItem item; + private final Direction dir; + + public ItemUseFactory(BaseItem item) { + this(item, Direction.UP); + } + + public ItemUseFactory(BaseItem item, Direction dir) { + this.item = item; + this.dir = dir; + } + + @Override + public RegionFunction createFromContext(EditContext input) { + World world = ((EditSession) input.getDestination()).getWorld(); + return new ItemUseFunction(world, item, dir); + } + + @Override + public String toString() { + return "application of the item " + item.getType(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java b/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java new file mode 100644 index 0000000..12b5f29 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.factory; + +import com.sk89q.worldedit.extent.NullExtent; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.block.BlockReplace; +import com.sk89q.worldedit.function.pattern.Pattern; + +import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; + +public class ReplaceFactory implements Contextual { + private final Pattern fill; + + public ReplaceFactory(Pattern fill) { + this.fill = fill; + } + + @Override + public RegionFunction createFromContext(EditContext context) { + return new BlockReplace( + firstNonNull(context.getDestination(), new NullExtent()), + firstNonNull(context.getFill(), fill)); + } + + @Override + public String toString() { + return "replace blocks"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java b/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java new file mode 100644 index 0000000..f6effd1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.factory; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.generator.ForestGenerator; +import com.sk89q.worldedit.util.TreeGenerator; + +public final class TreeGeneratorFactory implements Contextual { + private final TreeGenerator.TreeType type; + + public TreeGeneratorFactory(TreeGenerator.TreeType type) { + this.type = type; + } + + @Override + public ForestGenerator createFromContext(EditContext input) { + return new ForestGenerator((EditSession) input.getDestination(), type); + } + + @Override + public String toString() { + return "tree of type " + type; + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java new file mode 100644 index 0000000..6dd4b91 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java @@ -0,0 +1,99 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; + +/** + * A super pickaxe mode that will remove blocks in an area. + */ +public class AreaPickaxe implements BlockTool { + + private final int range; + + public AreaPickaxe(int range) { + this.range = range; + } + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.superpickaxe.area"); + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + int ox = clicked.getBlockX(); + int oy = clicked.getBlockY(); + int oz = clicked.getBlockZ(); + BlockType initialType = clicked.getExtent().getBlock(clicked.toVector().toBlockPoint()).getBlockType(); + + if (initialType.getMaterial().isAir()) { + return false; + } + + if (initialType == BlockTypes.BEDROCK && !player.canDestroyBedrock()) { + return false; + } + + try (EditSession editSession = session.createEditSession(player)) { + editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop); + + try { + for (int x = ox - range; x <= ox + range; ++x) { + for (int y = oy - range; y <= oy + range; ++y) { + for (int z = oz - range; z <= oz + range; ++z) { + BlockVector3 pos = BlockVector3.at(x, y, z); + if (editSession.getBlock(pos).getBlockType() != initialType) { + continue; + } + + editSession.setBlock(pos, BlockTypes.AIR.getDefaultState()); + + ((World) clicked.getExtent()).queueBlockBreakEffect(server, pos, initialType, + clicked.toVector().toBlockPoint().distanceSq(pos)); + } + } + } + } catch (MaxChangedBlocksException e) { + player.printError(TranslatableComponent.of("worldedit.tool.max-block-changes")); + } finally { + session.remember(editSession); + } + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java b/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java new file mode 100644 index 0000000..bae810d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java @@ -0,0 +1,129 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.google.common.collect.Lists; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * A mode that cycles the data values of supported blocks. + */ +public class BlockDataCyler implements DoubleActionBlockTool { + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.tool.data-cycler"); + } + + private final Map> selectedProperties = new HashMap<>(); + + private boolean handleCycle(LocalConfiguration config, Player player, LocalSession session, + Location clicked, boolean forward) { + + World world = (World) clicked.getExtent(); + + BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); + BaseBlock block = world.getFullBlock(blockPoint); + + if (!config.allowedDataCycleBlocks.isEmpty() + && !player.hasPermission("worldedit.override.data-cycler") + && !config.allowedDataCycleBlocks.contains(block.getBlockType().getId())) { + player.printError(TranslatableComponent.of("worldedit.tool.data-cycler.block-not-permitted")); + return true; + } + + if (block.getStates().keySet().isEmpty()) { + player.printError(TranslatableComponent.of("worldedit.tool.data-cycler.cant-cycle")); + } else { + Property currentProperty = selectedProperties.get(player.getUniqueId()); + + if (currentProperty == null || (forward && block.getState(currentProperty) == null)) { + currentProperty = block.getStates().keySet().stream().findFirst().get(); + selectedProperties.put(player.getUniqueId(), currentProperty); + } + + if (forward) { + block.getState(currentProperty); + int index = currentProperty.getValues().indexOf(block.getState(currentProperty)); + index = (index + 1) % currentProperty.getValues().size(); + @SuppressWarnings("unchecked") + Property objProp = (Property) currentProperty; + BaseBlock newBlock = block.with(objProp, currentProperty.getValues().get(index)); + + try (EditSession editSession = session.createEditSession(player)) { + editSession.disableBuffering(); + + try { + editSession.setBlock(blockPoint, newBlock); + player.printInfo(TranslatableComponent.of( + "worldedit.tool.data-cycler.new-value", + TextComponent.of(currentProperty.getName()), + TextComponent.of(String.valueOf(currentProperty.getValues().get(index))) + )); + } catch (MaxChangedBlocksException e) { + player.printError(TranslatableComponent.of("worldedit.tool.max-block-changes")); + } finally { + session.remember(editSession); + } + } + } else { + List> properties = Lists.newArrayList(block.getStates().keySet()); + int index = properties.indexOf(currentProperty); + index = (index + 1) % properties.size(); + currentProperty = properties.get(index); + selectedProperties.put(player.getUniqueId(), currentProperty); + player.printInfo(TranslatableComponent.of("worldedit.tool.data-cycler.cycling", TextComponent.of(currentProperty.getName()))); + } + } + + return true; + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + return handleCycle(config, player, session, clicked, true); + } + + @Override + public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + return handleCycle(config, player, session, clicked, false); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java b/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java new file mode 100644 index 0000000..dfefbd9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java @@ -0,0 +1,90 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.block.BaseBlock; + +import javax.annotation.Nullable; + +/** + * A mode that replaces one block. + */ +public class BlockReplacer implements DoubleActionBlockTool { + + private Pattern pattern; + + public BlockReplacer(Pattern pattern) { + this.pattern = pattern; + } + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.tool.replacer"); + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + BlockBag bag = session.getBlockBag(player); + + try (EditSession editSession = session.createEditSession(player)) { + try { + editSession.disableBuffering(); + BlockVector3 position = clicked.toVector().toBlockPoint(); + editSession.setBlock(position, pattern); + } catch (MaxChangedBlocksException ignored) { + } finally { + session.remember(editSession); + } + } finally { + if (bag != null) { + bag.flushChanges(); + } + } + + return true; + } + + + @Override + public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + BaseBlock targetBlock = player.getWorld().getFullBlock(clicked.toVector().toBlockPoint()); + + if (targetBlock != null) { + pattern = targetBlock; + player.printInfo(TranslatableComponent.of("worldedit.tool.repl.switched", targetBlock.getBlockType().getRichName())); + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java b/src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java new file mode 100644 index 0000000..a1c17c1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; + +import javax.annotation.Nullable; + +public interface BlockTool extends Tool { + + /** + * Perform the primary action of this tool. + * + * @return true to cancel the original event which triggered this action (if possible) + * @deprecated New subclasses should override {@link #actPrimary(Platform, LocalConfiguration, Player, LocalSession, + * Location, Direction)} instead + */ + @Deprecated + default boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { + return actPrimary(server, config, player, session, clicked, null); + } + + /** + * Perform the primary action of this tool. + * + * @param server The platform + * @param config The config instance + * @param player The player + * @param session The local session + * @param clicked The location that was clicked + * @param face The face that was clicked + * @return true to cancel the original event which triggered this action (if possible) + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "actPrimary", + delegateParams = { Platform.class, LocalConfiguration.class, Player.class, LocalSession.class, Location.class } + ) + default boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + DeprecationUtil.checkDelegatingOverride(getClass()); + return actPrimary(server, config, player, session, clicked); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java b/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java new file mode 100644 index 0000000..3c4d260 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java @@ -0,0 +1,224 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.command.tool.brush.Brush; +import com.sk89q.worldedit.command.tool.brush.SphereBrush; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.MaskIntersection; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TranslatableComponent; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Builds a shape at the place being looked at. + */ +public class BrushTool implements TraceTool { + + protected static int MAX_RANGE = 500; + protected int range = -1; + private Mask mask = null; + private Mask traceMask = null; + private Brush brush = new SphereBrush(); + @Nullable + private Pattern material; + private double size = 1; + private String permission; + + /** + * Construct the tool. + * + * @param permission the permission to check before use is allowed + */ + public BrushTool(String permission) { + checkNotNull(permission); + this.permission = permission; + } + + @Override + public boolean canUse(Actor player) { + return player.hasPermission(permission); + } + + /** + * Get the filter. + * + * @return the filter + */ + public Mask getMask() { + return mask; + } + + /** + * Set the block filter used for identifying blocks to replace. + * + * @param filter the filter to set + */ + public void setMask(Mask filter) { + this.mask = filter; + } + + /** + * Get the mask used for identifying where to stop traces. + * + * @return the mask used to stop block traces + */ + public @Nullable Mask getTraceMask() { + return this.traceMask; + } + + /** + * Set the block mask used for identifying where to stop traces. + * + * @param traceMask the mask used to stop block traces + */ + public void setTraceMask(@Nullable Mask traceMask) { + this.traceMask = traceMask; + } + + /** + * Set the brush. + * + * @param brush the brush + * @param permission the permission + */ + public void setBrush(Brush brush, String permission) { + this.brush = brush; + this.permission = permission; + } + + /** + * Get the current brush. + * + * @return the current brush + */ + public Brush getBrush() { + return brush; + } + + /** + * Set the material. + * + * @param material the material + */ + public void setFill(@Nullable Pattern material) { + this.material = material; + } + + /** + * Get the material. + * + * @return the material + */ + @Nullable public Pattern getMaterial() { + return material; + } + + /** + * Get the set brush size. + * + * @return a radius + */ + public double getSize() { + return size; + } + + /** + * Set the set brush size. + * + * @param radius a radius + */ + public void setSize(double radius) { + this.size = radius; + } + + /** + * Get the set brush range. + * + * @return the range of the brush in blocks + */ + public int getRange() { + return (range < 0) ? MAX_RANGE : Math.min(range, MAX_RANGE); + } + + /** + * Set the set brush range. + * + * @param range the range of the brush in blocks + */ + public void setRange(int range) { + this.range = range; + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + Location target = player.getBlockTrace(getRange(), true, traceMask); + + if (target == null) { + player.printError(TranslatableComponent.of("worldedit.tool.no-block")); + return true; + } + + BlockBag bag = session.getBlockBag(player); + + try (EditSession editSession = session.createEditSession(player)) { + if (mask != null) { + Mask existingMask = editSession.getMask(); + + if (existingMask == null) { + editSession.setMask(mask); + } else if (existingMask instanceof MaskIntersection) { + ((MaskIntersection) existingMask).add(mask); + } else { + MaskIntersection newMask = new MaskIntersection(existingMask); + newMask.add(mask); + editSession.setMask(newMask); + } + } + + try { + brush.build(editSession, target.toVector().toBlockPoint(), material, size); + } catch (MaxChangedBlocksException e) { + player.printError(TranslatableComponent.of("worldedit.tool.max-block-changes")); + } finally { + session.remember(editSession); + } + } finally { + if (bag != null) { + bag.flushChanges(); + } + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java b/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java new file mode 100644 index 0000000..1525375 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java @@ -0,0 +1,88 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TranslatableComponent; + +/** + * A wand that can be used at a distance. + */ +public class DistanceWand extends BrushTool implements DoubleActionTraceTool { + + public DistanceWand() { + super("worldedit.selection.pos"); + } + + @Override + public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + Location target = getTarget(player); + if (target == null) { + return true; + } + + RegionSelector selector = session.getRegionSelector(player.getWorld()); + BlockVector3 blockPoint = target.toVector().toBlockPoint(); + if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) { + selector.explainPrimarySelection(player, session, blockPoint); + } + return true; + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + Location target = getTarget(player); + if (target == null) { + return true; + } + + RegionSelector selector = session.getRegionSelector(player.getWorld()); + BlockVector3 blockPoint = target.toVector().toBlockPoint(); + if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) { + selector.explainSecondarySelection(player, session, blockPoint); + } + return true; + } + + private Location getTarget(Player player) { + Location target; + Mask mask = getTraceMask(); + if (this.range > -1) { + target = player.getBlockTrace(getRange(), true, mask); + } else { + target = player.getBlockTrace(MAX_RANGE, false, mask); + } + + if (target == null) { + player.printError(TranslatableComponent.of("worldedit.tool.no-block")); + return null; + } + + return target; + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java b/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java new file mode 100644 index 0000000..6b5abdf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java @@ -0,0 +1,72 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; + +import javax.annotation.Nullable; + +/** + * Represents a block tool that also has a secondary/primary function. + */ +public interface DoubleActionBlockTool extends BlockTool { + + /** + * Perform the secondary action of this block tool. + * + * @return true to cancel the original event which triggered this action (if possible) + * @deprecated New subclasses must override {@link #actSecondary(Platform, LocalConfiguration, Player, LocalSession, + * Location, Direction)} instead + */ + @Deprecated + default boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { + return actSecondary(server, config, player, session, clicked, null); + } + + /** + * Perform the secondary action of this block tool. + * + * @param server The platform + * @param config The config instance + * @param player The player + * @param session The local session + * @param clicked The location that was clicked + * @param face The face that was clicked + * @return true to cancel the original event which triggered this action (if possible) + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "actSecondary", + delegateParams = { Platform.class, LocalConfiguration.class, Player.class, LocalSession.class, Location.class } + ) + default boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + DeprecationUtil.checkDelegatingOverride(getClass()); + return actSecondary(server, config, player, session, clicked); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java b/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java new file mode 100644 index 0000000..fd79ed9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Platform; + +/** + * Represents a trace tool that also has a secondary/primary function. + */ +public interface DoubleActionTraceTool extends TraceTool { + + /** + * Perform the secondary function of this tool. + * + * @param server The platform + * @param config The config instance + * @param player The player + * @param session The local session + * @return true to cancel the original event which triggered this action (if possible) + */ + boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session); + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java b/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java new file mode 100644 index 0000000..b5b6593 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java @@ -0,0 +1,159 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockCategories; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +/** + * A pickaxe mode that removes floating treetops (logs and leaves not connected + * to anything else). + */ +public class FloatingTreeRemover implements BlockTool { + private final int rangeSq; + + public FloatingTreeRemover() { + rangeSq = 100 * 100; + } + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.tool.deltree"); + } + + private boolean isTreeBlock(BlockType type) { + return BlockCategories.LEAVES.contains(type) + || BlockCategories.LOGS.contains(type) + || type == BlockTypes.RED_MUSHROOM_BLOCK + || type == BlockTypes.BROWN_MUSHROOM_BLOCK + || type == BlockTypes.MUSHROOM_STEM + || type == BlockTypes.VINE; + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, + Player player, LocalSession session, Location clicked, + @Nullable Direction face) { + + final World world = (World) clicked.getExtent(); + final BlockState state = world.getBlock(clicked.toVector().toBlockPoint()); + + if (!isTreeBlock(state.getBlockType())) { + player.printError(TranslatableComponent.of("worldedit.tool.deltree.not-tree")); + return true; + } + + try (EditSession editSession = session.createEditSession(player)) { + try { + final Set blockSet = bfs(world, clicked.toVector().toBlockPoint()); + if (blockSet == null) { + player.printError(TranslatableComponent.of("worldedit.tool.deltree.not-floating")); + return true; + } + + for (BlockVector3 blockVector : blockSet) { + final BlockState otherState = editSession.getBlock(blockVector); + if (isTreeBlock(otherState.getBlockType())) { + editSession.setBlock(blockVector, BlockTypes.AIR.getDefaultState()); + } + } + } catch (MaxChangedBlocksException e) { + player.printError(TranslatableComponent.of("worldedit.tool.max-block-changes")); + } finally { + session.remember(editSession); + } + } + + return true; + } + + private final BlockVector3[] recurseDirections = { + Direction.NORTH.toBlockVector(), + Direction.EAST.toBlockVector(), + Direction.SOUTH.toBlockVector(), + Direction.WEST.toBlockVector(), + Direction.UP.toBlockVector(), + Direction.DOWN.toBlockVector(), + }; + + /** + * Helper method. + * + * @param world the world that contains the tree + * @param origin any point contained in the floating tree + * @return a set containing all blocks in the tree/shroom or null if this is not a floating tree/shroom. + */ + private Set bfs(World world, BlockVector3 origin) { + final Set visited = new HashSet<>(); + final LinkedList queue = new LinkedList<>(); + + queue.addLast(origin); + visited.add(origin); + + while (!queue.isEmpty()) { + final BlockVector3 current = queue.removeFirst(); + for (BlockVector3 recurseDirection : recurseDirections) { + final BlockVector3 next = current.add(recurseDirection); + if (origin.distanceSq(next) > rangeSq) { + // Maximum range exceeded => stop walking + continue; + } + + if (visited.add(next)) { + BlockState state = world.getBlock(next); + if (state.getBlockType().getMaterial().isAir() || state.getBlockType() == BlockTypes.SNOW) { + continue; + } + if (isTreeBlock(state.getBlockType())) { + queue.addLast(next); + } else { + // we hit something solid - evaluate where we came from + final BlockType currentType = world.getBlock(current).getBlockType(); + if (!BlockCategories.LEAVES.contains(currentType) && currentType != BlockTypes.VINE) { + // log/shroom touching a wall/the ground => this is not a floating tree, bail out + return null; + } + } + } + } + } + + return visited; + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java b/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java new file mode 100644 index 0000000..dce8283 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java @@ -0,0 +1,117 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.HashSet; +import java.util.Set; +import javax.annotation.Nullable; + +/** + * A tool that flood fills blocks. + */ +public class FloodFillTool implements BlockTool { + + private final int range; + private final Pattern pattern; + + public FloodFillTool(int range, Pattern pattern) { + this.range = range; + this.pattern = pattern; + } + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.tool.flood-fill"); + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + World world = (World) clicked.getExtent(); + + BlockVector3 origin = clicked.toVector().toBlockPoint(); + BlockType initialType = world.getBlock(origin).getBlockType(); + + if (initialType.getMaterial().isAir()) { + return true; + } + + if (initialType == BlockTypes.BEDROCK && !player.canDestroyBedrock()) { + return true; + } + + try (EditSession editSession = session.createEditSession(player)) { + try { + recurse(editSession, origin, origin, range, initialType, new HashSet<>()); + } catch (MaxChangedBlocksException e) { + player.printError(TranslatableComponent.of("worldedit.tool.max-block-changes")); + } finally { + session.remember(editSession); + } + } + + return true; + } + + private void recurse(EditSession editSession, BlockVector3 pos, BlockVector3 origin, int size, BlockType initialType, + Set visited) throws MaxChangedBlocksException { + + if (origin.distance(pos) > size || visited.contains(pos)) { + return; + } + + visited.add(pos); + + if (editSession.getBlock(pos).getBlockType() == initialType) { + editSession.setBlock(pos, pattern.applyBlock(pos)); + } else { + return; + } + + recurse(editSession, pos.add(1, 0, 0), + origin, size, initialType, visited); + recurse(editSession, pos.add(-1, 0, 0), + origin, size, initialType, visited); + recurse(editSession, pos.add(0, 0, 1), + origin, size, initialType, visited); + recurse(editSession, pos.add(0, 0, -1), + origin, size, initialType, visited); + recurse(editSession, pos.add(0, 1, 0), + origin, size, initialType, visited); + recurse(editSession, pos.add(0, -1, 0), + origin, size, initialType, visited); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/InvalidToolBindException.java b/src/main/java/com/sk89q/worldedit/command/tool/InvalidToolBindException.java new file mode 100644 index 0000000..f9f87cf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/InvalidToolBindException.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.Component; +import com.sk89q.worldedit.world.item.ItemType; + +public class InvalidToolBindException extends WorldEditException { + + private final ItemType item; + + public InvalidToolBindException(ItemType item, Component msg) { + super(msg); + this.item = item; + } + + @Deprecated + public InvalidToolBindException(ItemType item, String msg) { + super(msg); + this.item = item; + } + + public ItemType getItemType() { + return this.item; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java b/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java new file mode 100644 index 0000000..2dd9eb5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java @@ -0,0 +1,133 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.block.BaseBlock; + +/** + * A tool that can place (or remove) blocks at a distance. + */ +public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTool { + + private final Pattern primary; + private final Pattern secondary; + + public LongRangeBuildTool(Pattern secondary, Pattern primary) { + super("worldedit.tool.lrbuild"); + this.primary = primary; + this.secondary = secondary; + } + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.tool.lrbuild"); + } + + @Override + public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + Location pos = getTargetFace(player); + if (pos == null) { + return false; + } + BlockBag bag = session.getBlockBag(player); + + try (EditSession editSession = session.createEditSession(player)) { + try { + editSession.disableBuffering(); + BlockVector3 blockPoint = pos.toVector().toBlockPoint(); + BaseBlock applied = secondary.applyBlock(blockPoint); + if (applied.getBlockType().getMaterial().isAir()) { + editSession.setBlock(blockPoint, secondary); + } else { + editSession.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), secondary); + } + } catch (MaxChangedBlocksException ignored) { + } finally { + session.remember(editSession); + } + } finally { + if (bag != null) { + bag.flushChanges(); + } + } + return true; + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + Location pos = getTargetFace(player); + if (pos == null) { + return false; + } + BlockBag bag = session.getBlockBag(player); + + try (EditSession editSession = session.createEditSession(player)) { + try { + editSession.disableBuffering(); + BlockVector3 blockPoint = pos.toVector().toBlockPoint(); + BaseBlock applied = primary.applyBlock(blockPoint); + if (applied.getBlockType().getMaterial().isAir()) { + editSession.setBlock(blockPoint, primary); + } else { + editSession.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), primary); + } + } catch (MaxChangedBlocksException ignored) { + } finally { + session.remember(editSession); + } + } finally { + if (bag != null) { + bag.flushChanges(); + } + } + return true; + } + + private Location getTargetFace(Player player) { + Location target; + Mask mask = getTraceMask(); + if (this.range > -1) { + target = player.getBlockTrace(getRange(), true, mask); + } else { + target = player.getBlockTrace(MAX_RANGE, false, mask); + } + + if (target == null) { + player.printError(TranslatableComponent.of("worldedit.tool.no-block")); + return null; + } + + return target; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/NavigationWand.java b/src/main/java/com/sk89q/worldedit/command/tool/NavigationWand.java new file mode 100644 index 0000000..8c6f7f5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/NavigationWand.java @@ -0,0 +1,73 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TranslatableComponent; + +public class NavigationWand implements DoubleActionTraceTool { + + private static final String PRIMARY_PERMISSION = "worldedit.navigation.thru.tool"; + private static final String SECONDARY_PERMISSION = "worldedit.navigation.jumpto.tool"; + + @Override + public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + if (!player.hasPermission(SECONDARY_PERMISSION)) { + return false; + } + final int maxDist = config.navigationWandMaxDistance; + if (maxDist <= 0) { + return false; + } + Location pos = player.getSolidBlockTrace(maxDist); + if (pos != null) { + player.findFreePosition(pos); + } else { + player.printError(TranslatableComponent.of("worldedit.jumpto.none")); + } + return true; + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + if (!player.hasPermission(PRIMARY_PERMISSION)) { + return false; + } + final int maxDist = config.navigationWandMaxDistance; + if (maxDist <= 0) { + return false; + } + + if (!player.passThroughForwardWall(Math.max(1, maxDist - 10))) { + player.printError(TranslatableComponent.of("worldedit.thru.obstructed")); + } + return true; + } + + @Override + public boolean canUse(Actor actor) { + return actor.hasPermission(PRIMARY_PERMISSION) || actor.hasPermission(SECONDARY_PERMISSION); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java b/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java new file mode 100644 index 0000000..4c0e073 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java @@ -0,0 +1,85 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.registry.LegacyMapper; + +import javax.annotation.Nullable; + +/** + * Looks up information about a block. + */ +public class QueryTool implements BlockTool { + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.tool.info"); + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + + World world = (World) clicked.getExtent(); + EditSession editSession = session.createEditSession(player); + BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); + BaseBlock block = editSession.getFullBlock(blockPoint); + + TextComponent.Builder builder = TextComponent.builder(); + builder.append(TextComponent.of("@" + clicked.toVector().toBlockPoint() + ": ", TextColor.BLUE)); + builder.append(block.getBlockType().getRichName().color(TextColor.YELLOW)); + builder.append(TextComponent.of(" (" + block + ") ", TextColor.GRAY) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TranslatableComponent.of("worldedit.tool.info.blockstate.hover")))); + final int internalId = BlockStateIdAccess.getBlockStateId(block.toImmutableState()); + if (BlockStateIdAccess.isValidInternalId(internalId)) { + builder.append(TextComponent.of(" (" + internalId + ") ", TextColor.DARK_GRAY) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TranslatableComponent.of("worldedit.tool.info.internalid.hover")))); + } + final int[] legacy = LegacyMapper.getInstance().getLegacyFromBlock(block.toImmutableState()); + if (legacy != null) { + builder.append(TextComponent.of(" (" + legacy[0] + ":" + legacy[1] + ") ", TextColor.DARK_GRAY) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TranslatableComponent.of("worldedit.tool.info.legacy.hover")))); + } + + builder.append(TextComponent.of(" (" + world.getBlockLightLevel(blockPoint) + "/" + + world.getBlockLightLevel(blockPoint.add(0, 1, 0)) + ")", TextColor.WHITE) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TranslatableComponent.of("worldedit.tool.info.light.hover")))); + + player.print(builder.build()); + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java new file mode 100644 index 0000000..5afb055 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java @@ -0,0 +1,121 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.Set; + +/** + * A pickaxe mode that recursively finds adjacent blocks within range of + * an initial block and of the same type. + */ +public class RecursivePickaxe implements BlockTool { + + private final double range; + + public RecursivePickaxe(double range) { + this.range = range; + } + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.superpickaxe.recursive"); + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + World world = (World) clicked.getExtent(); + + BlockVector3 origin = clicked.toVector().toBlockPoint(); + BlockType initialType = world.getBlock(origin).getBlockType(); + + if (initialType.getMaterial().isAir()) { + return false; + } + + if (initialType == BlockTypes.BEDROCK && !player.canDestroyBedrock()) { + return false; + } + + try (EditSession editSession = session.createEditSession(player)) { + editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop); + + try { + recurse(server, editSession, world, clicked.toVector().toBlockPoint(), + clicked.toVector().toBlockPoint(), range, initialType, new HashSet<>()); + } catch (MaxChangedBlocksException e) { + player.printError(TranslatableComponent.of("worldedit.tool.max-block-changes")); + } finally { + session.remember(editSession); + } + } + + return true; + } + + private static void recurse(Platform server, EditSession editSession, World world, BlockVector3 pos, + BlockVector3 origin, double size, BlockType initialType, Set visited) throws MaxChangedBlocksException { + + final double distanceSq = origin.distanceSq(pos); + if (distanceSq > size * size || visited.contains(pos)) { + return; + } + + visited.add(pos); + + if (editSession.getBlock(pos).getBlockType() != initialType) { + return; + } + + editSession.setBlock(pos, BlockTypes.AIR.getDefaultState()); + + world.queueBlockBreakEffect(server, pos, initialType, distanceSq); + + recurse(server, editSession, world, pos.add(1, 0, 0), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(-1, 0, 0), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, 0, 1), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, 0, -1), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, 1, 0), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, -1, 0), + origin, size, initialType, visited); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java b/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java new file mode 100644 index 0000000..8268a4d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java @@ -0,0 +1,63 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; + +import javax.annotation.Nullable; + +public class SelectionWand implements DoubleActionBlockTool { + + @Override + public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + RegionSelector selector = session.getRegionSelector(player.getWorld()); + BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); + + if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) { + selector.explainPrimarySelection(player, session, blockPoint); + } + return true; + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + RegionSelector selector = session.getRegionSelector(player.getWorld()); + BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); + + if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) { + selector.explainSecondarySelection(player, session, blockPoint); + } + return true; + } + + @Override + public boolean canUse(Actor actor) { + return actor.hasPermission("worldedit.selection.pos"); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java new file mode 100644 index 0000000..9e8ecd9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; + +/** + * A super pickaxe mode that removes one block. + */ +public class SinglePickaxe implements BlockTool { + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.superpickaxe"); + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + World world = (World) clicked.getExtent(); + BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); + final BlockType blockType = world.getBlock(blockPoint).getBlockType(); + if (blockType == BlockTypes.BEDROCK && !player.canDestroyBedrock()) { + return false; + } + + try (EditSession editSession = session.createEditSession(player)) { + editSession.getSurvivalExtent().setToolUse(config.superPickaxeDrop); + editSession.setBlock(blockPoint, BlockTypes.AIR.getDefaultState()); + } catch (MaxChangedBlocksException e) { + player.printError(TranslatableComponent.of("worldedit.tool.max-block-changes")); + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java b/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java new file mode 100644 index 0000000..b9ad98f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java @@ -0,0 +1,85 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; + +public class StackTool implements BlockTool { + + private final int range; + private final Mask mask; + + public StackTool(int range, Mask mask) { + this.range = range; + this.mask = mask; + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + if (face == null) { + return false; + } + BlockBag bag = session.getBlockBag(player); + + try (EditSession editSession = session.createEditSession(player)) { + BlockStateHolder block = editSession.getFullBlock(clicked.toVector().toBlockPoint()); + + try { + editSession.disableBuffering(); + BlockVector3 position = clicked.toVector().toBlockPoint(); + for (int i = 0; i < range; i++) { + position = position.add(face.toBlockVector()); + if (!mask.test(position)) { + break; + } + editSession.setBlock(position, block); + } + } catch (MaxChangedBlocksException ignored) { + } finally { + session.remember(editSession); + } + } finally { + if (bag != null) { + bag.flushChanges(); + } + } + + return true; + } + + @Override + public boolean canUse(Actor actor) { + return actor.hasPermission("worldedit.tool.stack"); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/Tool.java b/src/main/java/com/sk89q/worldedit/command/tool/Tool.java new file mode 100644 index 0000000..2fa2b7b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/Tool.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.extension.platform.Actor; + +/** + * Represents a tool. This interface alone defines nothing. A tool also + * has to implement {@code BlockTool} or {@code TraceTool}. + */ +public interface Tool { + + /** + * Checks to see if the player can still be using this tool (considering + * permissions and such). + * + * @param actor the actor + * @return true if use is permitted + */ + boolean canUse(Actor actor); + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java b/src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java new file mode 100644 index 0000000..7addce0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Platform; + +public interface TraceTool extends Tool { + + /** + * Perform the primary action of this trace tool. + * + * @param server The platform + * @param config The config instance + * @param player The player + * @param session The local session + * @return true to cancel the original event which triggered this action (if possible) + */ + boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session); +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java b/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java new file mode 100644 index 0000000..b3df0f6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.TreeGenerator; +import net.kyori.text.TranslatableComponent; + +import javax.annotation.Nullable; + +/** + * Plants a tree. + */ +public class TreePlanter implements BlockTool { + + private final TreeGenerator.TreeType treeType; + + public TreePlanter(TreeGenerator.TreeType treeType) { + this.treeType = treeType; + } + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.tool.tree"); + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked, @Nullable Direction face) { + + try (EditSession editSession = session.createEditSession(player)) { + try { + boolean successful = false; + + final BlockVector3 pos = clicked.toVector().add(0, 1, 0).toBlockPoint(); + for (int i = 0; i < 10; i++) { + if (treeType.generate(editSession, pos)) { + successful = true; + break; + } + } + + if (!successful) { + player.printError(TranslatableComponent.of("worldedit.tool.tree.obstructed")); + } + } catch (MaxChangedBlocksException e) { + player.printError(TranslatableComponent.of("worldedit.tool.max-block-changes")); + } finally { + session.remember(editSession); + } + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java new file mode 100644 index 0000000..d7ff8c9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; + +/** + * A brush is a long-range build tool. + */ +public interface Brush { + + /** + * Build the object. + * + * @param editSession the {@code EditSession} + * @param position the position + * @param pattern the pattern + * @param size the size of the brush + * @throws MaxChangedBlocksException if the maximum block change limit is exceeded + */ + void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException; + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java new file mode 100644 index 0000000..32b2b9f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.command.util.CreatureButcher; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.visitor.EntityVisitor; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CylinderRegion; + +import java.util.List; + +public class ButcherBrush implements Brush { + + private final CreatureButcher flags; + + public ButcherBrush(CreatureButcher flags) { + this.flags = flags; + } + + @Override + public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { + CylinderRegion region = CylinderRegion.createRadius(editSession, position, size); + List entities = editSession.getEntities(region); + Operations.completeLegacy(new EntityVisitor(entities.iterator(), flags.createFunction())); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java new file mode 100644 index 0000000..318ef9e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java @@ -0,0 +1,79 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; + +public class ClipboardBrush implements Brush { + + private final ClipboardHolder holder; + private final boolean ignoreAirBlocks; + private final boolean usingOrigin; + private final boolean pasteEntities; + private final boolean pasteBiomes; + private final Mask sourceMask; + + public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks, boolean usingOrigin) { + this.holder = holder; + this.ignoreAirBlocks = ignoreAirBlocks; + this.usingOrigin = usingOrigin; + this.pasteBiomes = false; + this.pasteEntities = false; + this.sourceMask = null; + } + + public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks, boolean usingOrigin, boolean pasteEntities, + boolean pasteBiomes, Mask sourceMask) { + this.holder = holder; + this.ignoreAirBlocks = ignoreAirBlocks; + this.usingOrigin = usingOrigin; + this.pasteEntities = pasteEntities; + this.pasteBiomes = pasteBiomes; + this.sourceMask = sourceMask; + } + + @Override + public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { + Clipboard clipboard = holder.getClipboard(); + Region region = clipboard.getRegion(); + BlockVector3 centerOffset = region.getCenter().toBlockPoint().subtract(clipboard.getOrigin()); + + Operation operation = holder + .createPaste(editSession) + .to(usingOrigin ? position : position.subtract(centerOffset)) + .ignoreAirBlocks(ignoreAirBlocks) + .copyEntities(pasteEntities) + .copyBiomes(pasteBiomes) + .maskSource(sourceMask) + .build(); + + Operations.completeLegacy(operation); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java new file mode 100644 index 0000000..9217066 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockTypes; + +public class CylinderBrush implements Brush { + + private final int height; + + public CylinderBrush(int height) { + this.height = height; + } + + @Override + public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { + if (pattern == null) { + pattern = BlockTypes.COBBLESTONE.getDefaultState(); + } + editSession.makeCylinder(position, pattern, size, size, height, true); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java new file mode 100644 index 0000000..f113579 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java @@ -0,0 +1,105 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.LocatedBlock; +import com.sk89q.worldedit.util.collection.LocatedBlockList; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.LinkedHashSet; +import java.util.Set; + +public class GravityBrush implements Brush { + + private final boolean overrideHeight; + private final int heightOffset; + + public GravityBrush(Integer heightOffset) { + this.overrideHeight = heightOffset != null; + this.heightOffset = heightOffset != null ? heightOffset : Integer.MIN_VALUE; + } + + @Override + public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { + double sizeOffset = overrideHeight ? heightOffset : size; + double yMax = Math.min(position.getY() + sizeOffset, editSession.getWorld().getMaxY()); + double yMin = Math.max(position.getY() - sizeOffset, editSession.getWorld().getMinY()); + LocatedBlockList column = new LocatedBlockList(); + Set removedBlocks = new LinkedHashSet<>(); + for (double x = position.getX() - size; x <= position.getX() + size; x++) { + for (double z = position.getZ() - size; z <= position.getZ() + size; z++) { + /* + * Algorithm: + * 1. Find the lowest air block in the selection -> $lowestAir = position + * 2. Move the first non-air block above it down to $lowestAir + * 3. Add 1 to $lowestAir's y-coord. + * 4. If more blocks above current position, repeat from 2 + */ + + BlockVector3 lowestAir = null; + for (double y = yMin; y <= yMax; y++) { + BlockVector3 pt = BlockVector3.at(x, y, z); + + BaseBlock block = editSession.getFullBlock(pt); + + if (block.getBlockType().getMaterial().isAir()) { + if (lowestAir == null) { + // we found the lowest air block + lowestAir = pt; + } + continue; + } + + if (lowestAir == null) { + // no place to move the block to + continue; + } + + BlockVector3 newPos = lowestAir; + // we know the block above must be air, + // since either this block is being moved into it, + // or there has been more air before this block + lowestAir = lowestAir.add(0, 1, 0); + + removedBlocks.remove(newPos); + column.add(newPos, block); + removedBlocks.add(pt); + } + + for (LocatedBlock block : column) { + editSession.setBlock(block.getLocation(), block.getBlock()); + } + + for (BlockVector3 removedBlock : removedBlocks) { + editSession.setBlock(removedBlock, BlockTypes.AIR.getDefaultState()); + } + + column.clear(); + removedBlocks.clear(); + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java new file mode 100644 index 0000000..c390501 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockTypes; + +public class HollowCylinderBrush implements Brush { + + private final int height; + + public HollowCylinderBrush(int height) { + this.height = height; + } + + @Override + public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { + if (pattern == null) { + pattern = BlockTypes.COBBLESTONE.getDefaultState(); + } + editSession.makeCylinder(position, pattern, size, size, height, false); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java new file mode 100644 index 0000000..63cb9eb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockTypes; + +public class HollowSphereBrush implements Brush { + + @Override + public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { + if (pattern == null) { + pattern = BlockTypes.COBBLESTONE.getDefaultState(); + } + editSession.makeSphere(position, pattern, size, size, size, false); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/ImageHeightmapBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ImageHeightmapBrush.java new file mode 100644 index 0000000..71562b9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/ImageHeightmapBrush.java @@ -0,0 +1,83 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.asset.holder.ImageHeightmap; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.concurrent.ThreadLocalRandom; + +public class ImageHeightmapBrush implements Brush { + + private final ImageHeightmap heightmap; + private final double intensity; + private final boolean erase; + private final boolean flatten; + private final boolean randomize; + + public ImageHeightmapBrush(ImageHeightmap heightmap, double intensity, boolean erase, boolean flatten, boolean randomize) { + this.heightmap = heightmap; + this.intensity = intensity; + this.erase = erase; + this.flatten = flatten; + this.randomize = randomize; + } + + @Override + public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double doubleSize) throws MaxChangedBlocksException { + int size = (int) Math.ceil(doubleSize); + + double random = randomize ? ThreadLocalRandom.current().nextDouble() : 0; + for (int offX = -size; offX <= size; offX++) { + for (int offZ = -size; offZ <= size; offZ++) { + int posX = position.getX() + offX; + int posZ = position.getZ() + offZ; + int posY = editSession.getHighestTerrainBlock(posX, posZ, 0, 255, editSession.getMask()); + BlockVector3 block = BlockVector3.at(posX, posY, posZ); + if (editSession.getMask() != null && !editSession.getMask().test(block)) { + continue; + } + + double height = heightmap.getHeightAt(offX + size, offZ + size, size * 2 + 1) * intensity; + // Add a bit of variation + if (randomize && random > 1 - height % 1) { + height += 1; + } + + BlockState baseBlock = erase ? null : editSession.getBlock(block); + for (int y = 0; y < height; y++) { + if (erase) { + // Remove blocks if using the erase flag + if (!flatten || block.getY() - y > position.getY()) { + editSession.setBlock(block.withY(block.getY() - y), BlockTypes.AIR.getDefaultState()); + } + } else if (!flatten || block.getY() + y <= position.getY()) { + editSession.setBlock(block.withY(block.getY() + y), baseBlock); + } + } + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/OperationFactoryBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/OperationFactoryBrush.java new file mode 100644 index 0000000..6889135 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/OperationFactoryBrush.java @@ -0,0 +1,60 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.factory.RegionFactory; + +public class OperationFactoryBrush implements Brush { + + private final Contextual operationFactory; + private final RegionFactory regionFactory; + private final LocalSession session; + + public OperationFactoryBrush(Contextual operationFactory, RegionFactory regionFactory) { + this(operationFactory, regionFactory, null); + } + + public OperationFactoryBrush(Contextual operationFactory, RegionFactory regionFactory, LocalSession session) { + this.operationFactory = operationFactory; + this.regionFactory = regionFactory; + this.session = session; + } + + @Override + public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { + EditContext context = new EditContext(); + context.setDestination(editSession); + context.setRegion(regionFactory.createCenteredAt(position, size)); + context.setFill(pattern); + context.setSession(session); + Operation operation = operationFactory.createFromContext(context); + Operations.completeLegacy(operation); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/SmoothBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/SmoothBrush.java new file mode 100644 index 0000000..e92b929 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/SmoothBrush.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.convolution.GaussianKernel; +import com.sk89q.worldedit.math.convolution.HeightMap; +import com.sk89q.worldedit.math.convolution.HeightMapFilter; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; + +import javax.annotation.Nullable; + +public class SmoothBrush implements Brush { + + private final Mask mask; + private final int iterations; + + public SmoothBrush(int iterations) { + this(iterations, null); + } + + public SmoothBrush(int iterations, @Nullable Mask mask) { + this.iterations = iterations; + this.mask = mask; + } + + @Override + public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { + Vector3 posDouble = position.toVector3(); + Location min = new Location(editSession.getWorld(), posDouble.subtract(size, size, size)); + BlockVector3 max = posDouble.add(size, size + 10, size).toBlockPoint(); + Region region = new CuboidRegion(editSession.getWorld(), min.toVector().toBlockPoint(), max); + HeightMap heightMap = new HeightMap(editSession, region, mask); + HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); + heightMap.applyFilter(filter, iterations); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java new file mode 100644 index 0000000..1838ee1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockTypes; + +public class SphereBrush implements Brush { + + @Override + public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { + if (pattern == null) { + pattern = BlockTypes.COBBLESTONE.getDefaultState(); + } + editSession.makeSphere(position, pattern, size, size, size, true); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java b/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java new file mode 100644 index 0000000..98e63c9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java @@ -0,0 +1,222 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.util.formatting.component.ErrorFormat; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.task.FutureForwardingTask; +import com.sk89q.worldedit.util.task.Supervisor; +import org.apache.logging.log4j.Logger; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.CommandExecutionException; + +import java.util.concurrent.Callable; +import java.util.function.Consumer; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +public final class AsyncCommandBuilder { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final Callable callable; + private final Actor sender; + + @Nullable + private Supervisor supervisor; + @Nullable + private String description; + @Nullable + private Component delayMessage; + @Nullable + private Component workingMessage; + + @Nullable + private Component successMessage; + @Nullable + private Consumer consumer; + + @Nullable + private Component failureMessage; + @Nullable + private ExceptionConverter exceptionConverter; + + private AsyncCommandBuilder(Callable callable, Actor sender) { + checkNotNull(callable); + checkNotNull(sender); + this.callable = callable; + this.sender = sender; + } + + public static AsyncCommandBuilder wrap(Callable callable, Actor sender) { + return new AsyncCommandBuilder<>(callable, sender); + } + + public AsyncCommandBuilder registerWithSupervisor(Supervisor supervisor, String description) { + this.supervisor = checkNotNull(supervisor); + this.description = checkNotNull(description); + return this; + } + + @Deprecated + public AsyncCommandBuilder sendMessageAfterDelay(String message) { + return sendMessageAfterDelay(TextComponent.of(checkNotNull(message))); + } + + @Deprecated + public AsyncCommandBuilder sendMessageAfterDelay(Component message) { + return setDelayMessage(message); + } + + public AsyncCommandBuilder setDelayMessage(Component message) { + this.delayMessage = checkNotNull(message); + return this; + } + + public AsyncCommandBuilder setWorkingMessage(Component message) { + checkNotNull(this.delayMessage, "Must have a delay message if using a working message"); + this.workingMessage = checkNotNull(message); + return this; + } + + public AsyncCommandBuilder onSuccess(@Nullable Component message, @Nullable Consumer consumer) { + checkArgument(message != null || consumer != null, "Can't have null message AND consumer"); + this.successMessage = message; + this.consumer = consumer; + return this; + } + + public AsyncCommandBuilder onSuccess(@Nullable String message, @Nullable Consumer consumer) { + checkArgument(message != null || consumer != null, "Can't have null message AND consumer"); + this.successMessage = message == null ? null : TextComponent.of(message, TextColor.LIGHT_PURPLE); + this.consumer = consumer; + return this; + } + + public AsyncCommandBuilder onFailure(@Nullable Component message, @Nullable ExceptionConverter exceptionConverter) { + checkArgument(message != null || exceptionConverter != null, "Can't have null message AND exceptionConverter"); + this.failureMessage = message; + this.exceptionConverter = exceptionConverter; + return this; + } + + public AsyncCommandBuilder onFailure(@Nullable String message, @Nullable ExceptionConverter exceptionConverter) { + checkArgument(message != null || exceptionConverter != null, "Can't have null message AND exceptionConverter"); + this.failureMessage = message == null ? null : ErrorFormat.wrap(message); + this.exceptionConverter = exceptionConverter; + return this; + } + + public ListenableFuture buildAndExec(ListeningExecutorService executor) { + final ListenableFuture future = checkNotNull(executor).submit(this::runTask); + if (delayMessage != null) { + FutureProgressListener.addProgressListener( + future, + sender, + delayMessage, + workingMessage + ); + } + if (supervisor != null && description != null) { + supervisor.monitor(FutureForwardingTask.create(future, description, sender)); + } + return future; + } + + @SuppressWarnings("deprecation") + private T runTask() { + T result = null; + try { + result = callable.call(); + if (consumer != null) { + consumer.accept(result); + } + if (successMessage != null) { + sender.print(successMessage); + } + } catch (Throwable orig) { + Component failure = failureMessage != null ? failureMessage : TextComponent.of("An error occurred"); + try { + if (exceptionConverter != null) { + try { + if (orig instanceof com.sk89q.minecraft.util.commands.CommandException) { + throw new CommandExecutionException(orig, ImmutableList.of()); + } + exceptionConverter.convert(orig); + throw orig; + } catch (CommandException converted) { + Component message; + + // TODO remove this once WG migrates to piston and can use piston exceptions everywhere + message = tryExtractOldCommandException(converted); + + if (message == null) { + if (Strings.isNullOrEmpty(converted.getMessage())) { + message = TextComponent.of("Unknown error."); + } else { + message = converted.getRichMessage(); + } + } + sender.printError(failure.append(TextComponent.of(": ")).append(message)); + } + } else { + throw orig; + } + } catch (Throwable unknown) { + sender.printError(failure.append(TextComponent.of(": Unknown error. Please see console."))); + LOGGER.error("Uncaught exception occurred in task: " + description, orig); + } + } + return result; + } + + // this is needed right now since worldguard is still on the 2011 command framework which throws and converts + // com.sk89q.minecraft.util.commands.CommandException. the ExceptionConverter currently expects converted + // exceptions to be org.enginehub.piston.CommandException, throw it wraps the resulting InvocationTargetException in + // a CommandExecutionException. here, we unwrap those layers to retrieve the original WG error message + @SuppressWarnings("deprecation") + private Component tryExtractOldCommandException(CommandException converted) { + Component message = null; + if (converted instanceof CommandExecutionException) { + Throwable parentCause = converted; + while ((parentCause = parentCause.getCause()) != null) { + if (parentCause instanceof com.sk89q.minecraft.util.commands.CommandException) { + final String msg = parentCause.getMessage(); + if (!Strings.isNullOrEmpty(msg)) { + message = TextComponent.of(msg); + } + break; + } + } + } + return message; + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/CommandPermissions.java b/src/main/java/com/sk89q/worldedit/command/util/CommandPermissions.java new file mode 100644 index 0000000..5b00768 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/CommandPermissions.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import org.enginehub.piston.annotation.CommandCondition; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +@CommandCondition(CommandPermissionsConditionGenerator.class) +public @interface CommandPermissions { + + /** + * A list of permissions. Only one permission has to be met + * for the command to be permitted. + * + * @return a list of permissions strings + */ + String[] value(); + +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java b/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java new file mode 100644 index 0000000..18e3479 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java @@ -0,0 +1,46 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.google.common.collect.ImmutableSet; +import org.enginehub.piston.Command; +import org.enginehub.piston.gen.CommandConditionGenerator; +import org.enginehub.piston.util.NonnullByDefault; + +import java.lang.reflect.Method; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +@NonnullByDefault +public final class CommandPermissionsConditionGenerator implements CommandConditionGenerator { + + public interface Registration { + Registration commandPermissionsConditionGenerator(CommandPermissionsConditionGenerator generator); + } + + @Override + public Command.Condition generateCondition(Method commandMethod) { + CommandPermissions annotation = commandMethod.getAnnotation(CommandPermissions.class); + checkNotNull(annotation, "Annotation is missing from commandMethod"); + Set permissions = ImmutableSet.copyOf(annotation.value()); + return new PermissionCondition(permissions); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java b/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java new file mode 100644 index 0000000..d19ad70 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java @@ -0,0 +1,130 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.sk89q.worldedit.entity.metadata.EntityProperties; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.EntityFunction; + +/** + * The implementation of /butcher. + */ +public class CreatureButcher { + + public final class Flags { + @SuppressWarnings("PointlessBitwiseExpression") + public static final int PETS = 1 << 0; + public static final int NPCS = 1 << 1; + public static final int ANIMALS = 1 << 2; + public static final int GOLEMS = 1 << 3; + public static final int AMBIENT = 1 << 4; + public static final int TAGGED = 1 << 5; + public static final int ARMOR_STAND = 1 << 6; + public static final int WATER = 1 << 7; + public static final int FRIENDLY = PETS | NPCS | ANIMALS | GOLEMS | AMBIENT | TAGGED | WATER; + + private Flags() { + } + } + + private final Actor player; + public int flags = 0; + + public CreatureButcher(Actor player) { + this.player = player; + } + + public void or(int flag, boolean on) { + if (on) { + flags |= flag; + } + } + + public void or(int flag, boolean on, String permission) { + or(flag, on); + + if ((flags & flag) != 0 && !player.hasPermission(permission)) { + flags &= ~flag; + } + } + + public EntityFunction createFunction() { + return entity -> { + boolean killPets = (flags & Flags.PETS) != 0; + boolean killNPCs = (flags & Flags.NPCS) != 0; + boolean killAnimals = (flags & Flags.ANIMALS) != 0; + boolean killGolems = (flags & Flags.GOLEMS) != 0; + boolean killAmbient = (flags & Flags.AMBIENT) != 0; + boolean killTagged = (flags & Flags.TAGGED) != 0; + boolean killArmorStands = (flags & Flags.ARMOR_STAND) != 0; + boolean killWaterCreatures = (flags & Flags.WATER) != 0; + + EntityProperties type = entity.getFacet(EntityProperties.class); + + if (type == null) { + return false; + } + + if (type.isPlayerDerived()) { + return false; + } + + if (!type.isLiving()) { + return false; + } + + if (!killAnimals && type.isAnimal()) { + return false; + } + + if (!killPets && type.isTamed()) { + return false; + } + + if (!killGolems && type.isGolem()) { + return false; + } + + if (!killNPCs && type.isNPC()) { + return false; + } + + if (!killAmbient && type.isAmbient()) { + return false; + } + + if (!killTagged && type.isTagged()) { + return false; + } + + if (!killArmorStands && type.isArmorStand()) { + return false; + } + + if (!killWaterCreatures && type.isWaterCreature()) { + return false; + } + + entity.remove(); + return true; + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java b/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java new file mode 100644 index 0000000..f2118cd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java @@ -0,0 +1,157 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.sk89q.worldedit.entity.metadata.EntityProperties; +import com.sk89q.worldedit.function.EntityFunction; + +import javax.annotation.Nullable; +import java.util.regex.Pattern; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The implementation of /remove. + */ +public class EntityRemover { + + public enum Type { + ALL("all") { + @Override + boolean matches(EntityProperties type) { + for (Type value : values()) { + if (value != this && value.matches(type)) { + return true; + } + } + return false; + } + }, + PROJECTILES("projectiles?|arrows?") { + @Override + boolean matches(EntityProperties type) { + return type.isProjectile(); + } + }, + ITEMS("items?|drops?") { + @Override + boolean matches(EntityProperties type) { + return type.isItem(); + } + }, + FALLING_BLOCKS("falling(blocks?|sand|gravel)") { + @Override + boolean matches(EntityProperties type) { + return type.isFallingBlock(); + } + }, + PAINTINGS("paintings?|art") { + @Override + boolean matches(EntityProperties type) { + return type.isPainting(); + } + }, + ITEM_FRAMES("(item)frames?") { + @Override + boolean matches(EntityProperties type) { + return type.isItemFrame(); + } + }, + BOATS("boats?") { + @Override + boolean matches(EntityProperties type) { + return type.isBoat(); + } + }, + MINECARTS("(mine)?carts?") { + @Override + boolean matches(EntityProperties type) { + return type.isMinecart(); + } + }, + TNT("tnt") { + @Override + boolean matches(EntityProperties type) { + return type.isTNT(); + } + }, + XP_ORBS("xp") { + @Override + boolean matches(EntityProperties type) { + return type.isExperienceOrb(); + } + }; + + private final Pattern pattern; + + Type(String pattern) { + this.pattern = Pattern.compile(pattern); + } + + public boolean matches(String str) { + return pattern.matcher(str).matches(); + } + + abstract boolean matches(EntityProperties type); + + @Nullable + public static Type findByPattern(String str) { + for (Type type : values()) { + if (type.matches(str)) { + return type; + } + } + + return null; + } + } + + public static EntityRemover fromString(String str) { + Type type = Type.findByPattern(str); + if (type != null) { + return new EntityRemover(type); + } else { + throw new IllegalArgumentException("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"); + } + } + + private final Type type; + + private EntityRemover(Type type) { + this.type = type; + } + + public EntityFunction createFunction() { + final Type type = this.type; + checkNotNull(type, "type can't be null"); + return entity -> { + EntityProperties registryType = entity.getFacet(EntityProperties.class); + if (registryType != null) { + if (type.matches(registryType)) { + entity.remove(); + return true; + } + } + + return false; + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/FutureProgressListener.java b/src/main/java/com/sk89q/worldedit/command/util/FutureProgressListener.java new file mode 100644 index 0000000..e2fdcdb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/FutureProgressListener.java @@ -0,0 +1,76 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import com.sk89q.worldedit.extension.platform.Actor; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; + +import java.util.Timer; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class FutureProgressListener implements Runnable { + + private static final Timer timer = new Timer(); + private static final int MESSAGE_DELAY = 1000; // 1 second + private static final int MESSAGE_PERIOD = 10000; // 10 seconds + + private final MessageTimerTask task; + + @Deprecated + public FutureProgressListener(Actor sender, String message) { + this(sender, TextComponent.of(message)); + } + + public FutureProgressListener(Actor sender, Component message) { + this(sender, message, null); + } + + public FutureProgressListener(Actor sender, Component message, @Nullable Component workingMessage) { + checkNotNull(sender); + checkNotNull(message); + + task = new MessageTimerTask(sender, message, workingMessage); + timer.scheduleAtFixedRate(task, MESSAGE_DELAY, MESSAGE_PERIOD); + } + + @Override + public void run() { + task.cancel(); + } + + @Deprecated + public static void addProgressListener(ListenableFuture future, Actor sender, String message) { + addProgressListener(future, sender, TextComponent.of(message)); + } + + public static void addProgressListener(ListenableFuture future, Actor sender, Component message) { + future.addListener(new FutureProgressListener(sender, message), MoreExecutors.directExecutor()); + } + + public static void addProgressListener(ListenableFuture future, Actor sender, Component message, Component workingMessage) { + future.addListener(new FutureProgressListener(sender, message, workingMessage), MoreExecutors.directExecutor()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/HookMode.java b/src/main/java/com/sk89q/worldedit/command/util/HookMode.java new file mode 100644 index 0000000..a2e4cd1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/HookMode.java @@ -0,0 +1,24 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +public enum HookMode { + ACTIVE, INACTIVE +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/Logging.java b/src/main/java/com/sk89q/worldedit/command/util/Logging.java new file mode 100644 index 0000000..aa04cfb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/Logging.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +//$Id$ + + +package com.sk89q.worldedit.command.util; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Indicates how the affected blocks should be hinted at in the log. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Logging { + + enum LogMode { + /** + * Player position. + */ + POSITION, + + /** + * Region selection. + */ + REGION, + + /** + * Player orientation and region selection. + */ + ORIENTATION_REGION, + + /** + * Either the player position or pos1, depending on the placeAtPos1 flag. + */ + PLACEMENT, + + /** + * Log all information available. + */ + ALL + } + + /** + * Log mode. + * + * @return either POSITION, REGION, ORIENTATION_REGION, PLACEMENT or ALL + */ + LogMode value(); + +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/MessageTimerTask.java b/src/main/java/com/sk89q/worldedit/command/util/MessageTimerTask.java new file mode 100644 index 0000000..828cd51 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/MessageTimerTask.java @@ -0,0 +1,66 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.sk89q.worldedit.extension.platform.Actor; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; + +import javax.annotation.Nullable; +import java.util.TimerTask; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class MessageTimerTask extends TimerTask { + + private final Actor sender; + private final Component message; + @Nullable + private final Component workingMessage; + + private boolean hasRunBefore = false; + + @Deprecated + MessageTimerTask(Actor sender, String message) { + this(sender, TextComponent.of(message), null); + } + + MessageTimerTask(Actor sender, Component message, @Nullable Component workingMessage) { + checkNotNull(sender); + checkNotNull(message); + + this.sender = sender; + this.message = message; + this.workingMessage = workingMessage; + } + + @Override + public void run() { + if (!hasRunBefore) { + sender.printDebug(message); + hasRunBefore = true; + } else if (workingMessage != null) { + sender.printDebug(workingMessage); + } else { + cancel(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java b/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java new file mode 100644 index 0000000..4bb9d51 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java @@ -0,0 +1,50 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.sk89q.worldedit.extension.platform.Actor; +import org.enginehub.piston.Command; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.Set; + +public class PermissionCondition implements Command.Condition { + + private static final Key ACTOR_KEY = Key.of(Actor.class); + + private final Set permissions; + + public PermissionCondition(Set permissions) { + this.permissions = permissions; + } + + public Set getPermissions() { + return permissions; + } + + @Override + public boolean satisfied(InjectedValueAccess context) { + return permissions.isEmpty() + || context.injectedValue(ACTOR_KEY) + .map(actor -> permissions.stream().anyMatch(actor::hasPermission)) + .orElse(false); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java new file mode 100644 index 0000000..1adceb3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -0,0 +1,166 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.formatting.component.CommandListBox; +import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; +import com.sk89q.worldedit.util.formatting.component.InvalidComponentException; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.inject.InjectedValueStore; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.inject.MapBackedValueStore; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.sk89q.worldedit.internal.command.CommandUtil.byCleanName; +import static com.sk89q.worldedit.internal.command.CommandUtil.getSubCommands; +import static java.util.stream.Collectors.toList; + +/** + * Implementation of the //help command. + */ +// Stored in a separate class to prevent import conflicts, and because it's aliased via /we help. +public class PrintCommandHelp { + + private static Command detectCommand(CommandManager manager, String command) { + Optional mapping; + + // First try the command as entered + mapping = manager.getCommand(command); + if (mapping.isPresent()) { + return mapping.get(); + } + + // If tried with slashes, try dropping a slash + if (command.startsWith("/")) { + mapping = manager.getCommand(command.substring(1)); + return mapping.orElse(null); + } + + // Otherwise, check /command, since that's common + mapping = manager.getCommand("/" + command); + return mapping.orElse(null); + } + + public static void help(List commandPath, int page, boolean listSubCommands, + CommandManager manager, Actor actor, String helpRootCommand) throws InvalidComponentException { + + if (commandPath.isEmpty()) { + printCommands(page, manager.getAllCommands(), actor, ImmutableList.of(), helpRootCommand); + return; + } + + List visited = new ArrayList<>(); + Command currentCommand = detectCommand(manager, commandPath.get(0)); + if (currentCommand == null) { + actor.printError(TranslatableComponent.of("worldedit.help.command-not-found", TextComponent.of(commandPath.get(0)))); + return; + } + visited.add(currentCommand); + + // Drill down to the command + for (int i = 1; i < commandPath.size(); i++) { + String subCommand = commandPath.get(i); + Map subCommands = getSubCommands(currentCommand); + + if (subCommands.isEmpty()) { + actor.printError(TranslatableComponent.of("worldedit.help.no-subcommands", + TextComponent.of(toCommandString(visited)), TextComponent.of(subCommand))); + // full help for single command + CommandUsageBox box = new CommandUsageBox(visited, visited.stream() + .map(Command::getName).collect(Collectors.joining(" ")), helpRootCommand); + actor.print(box.create()); + return; + } + + if (subCommands.containsKey(subCommand)) { + currentCommand = subCommands.get(subCommand); + visited.add(currentCommand); + } else { + actor.printError(TranslatableComponent.of("worldedit.help.subcommand-not-found", + TextComponent.of(subCommand), TextComponent.of(toCommandString(visited)))); + // list subcommands for currentCommand + printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited, helpRootCommand); + return; + } + } + + Map subCommands = getSubCommands(currentCommand); + + if (subCommands.isEmpty() || !listSubCommands) { + // Create the message + CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited), helpRootCommand); + actor.print(box.create()); + } else { + printCommands(page, subCommands.values().stream(), actor, visited, helpRootCommand); + } + } + + private static String toCommandString(List visited) { + return "/" + Joiner.on(" ").join(visited.stream().map(Command::getName).iterator()); + } + + private static void printCommands(int page, Stream commandStream, Actor actor, + List commandList, String helpRootCommand) throws InvalidComponentException { + InjectedValueStore store = MapBackedValueStore.create(); + store.injectValue(Key.of(Actor.class), context -> + Optional.of(actor)); + + // Get a list of aliases + List commands = commandStream + .filter(command -> command.getCondition().satisfied(store)) + .sorted(byCleanName()) + .collect(toList()); + + String used = commandList.isEmpty() ? null : toCommandString(commandList); + CommandListBox box = new CommandListBox( + (used == null ? "Help" : "Subcommands: " + used), + helpRootCommand + " -s -p %page%" + (used == null ? "" : " " + used), + helpRootCommand); + if (!actor.isPlayer()) { + box.formatForConsole(); + } + + for (Command mapping : commands) { + String alias = (commandList.isEmpty() ? "/" : "") + mapping.getName(); + String command = Stream.concat(commandList.stream(), Stream.of(mapping)) + .map(Command::getName) + .collect(Collectors.joining(" ", "/", "")); + box.appendCommand(alias, mapping.getDescription(), command); + } + + actor.print(box.create(page)); + } + + private PrintCommandHelp() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java b/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java new file mode 100644 index 0000000..c3ac2f5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.enginehub.piston.Command; +import org.enginehub.piston.inject.InjectedValueAccess; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public final class SubCommandPermissionCondition extends PermissionCondition { + + private final Command.Condition aggregate; + + private SubCommandPermissionCondition(Set perms, Command.Condition aggregate) { + super(perms); + this.aggregate = aggregate; + } + + @Override + public boolean satisfied(InjectedValueAccess context) { + return aggregate.satisfied(context); + } + + public static class Generator { + private final List subCommands; + + public Generator(Collection subCommands) { + this.subCommands = ImmutableList.copyOf(subCommands); + } + + public Command.Condition build() { + final List conditions = subCommands.stream().map(Command::getCondition).collect(Collectors.toList()); + final List> permConds = conditions.stream().map(c -> c.as(PermissionCondition.class)).collect(Collectors.toList()); + if (permConds.stream().anyMatch(o -> !o.isPresent())) { + // if any sub-command doesn't require permissions, then this command doesn't require permissions + return new PermissionCondition(ImmutableSet.of()); + } + // otherwise, this command requires any one subcommand to be available + final Set perms = permConds.stream().map(Optional::get).flatMap(cond -> cond.getPermissions().stream()).collect(Collectors.toSet()); + final Command.Condition aggregate = permConds.stream().map(Optional::get) + .map(c -> (Command.Condition) c) + .reduce(Command.Condition::or).orElse(TRUE); + return new SubCommandPermissionCondition(perms, aggregate); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java b/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java new file mode 100644 index 0000000..70375f2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java @@ -0,0 +1,179 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; +import com.sk89q.worldedit.registry.Registry; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.enginehub.piston.converter.SuggestionHelper.byPrefix; +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + +/** + * Internal class for generating common command suggestions. + */ +public final class SuggestionHelper { + private SuggestionHelper() { + } + + public static Stream getBlockCategorySuggestions(String tag, boolean allowRandom) { + if (tag.isEmpty() || tag.equals("#")) { + return allowRandom ? Stream.of("##", "##*") : Stream.of("##"); + } + if (tag.startsWith("##")) { + if (tag.equals("##")) { + return Stream.concat(allowRandom ? Stream.of("##*") : Stream.empty(), + getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(2)).map(s -> "##" + s)); + } else if (tag.equals("##*") && allowRandom) { + return getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(3)).map(s -> "##*" + s); + } else { + boolean wild = tag.startsWith("##*") && allowRandom; + return getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(wild ? 3 : 2)).map(s -> (wild ? "##*" : "##") + s); + } + } + return Stream.empty(); + } + + public static Stream getBlockPropertySuggestions(String blockType, String props) { + BlockType type = BlockTypes.get(blockType.toLowerCase(Locale.ROOT)); + if (type == null) { + return Stream.empty(); + } + if (!props.toLowerCase(Locale.ROOT).equals(props)) { + return Stream.empty(); + } + final Map> propertyMap = type.getPropertyMap(); + Set matchedProperties = new HashSet<>(); + String[] propParts = props.split(",", -1); + for (int i = 0; i < propParts.length; i++) { + String[] propVal = propParts[i].split("="); + final String matchProp = propVal[0].toLowerCase(Locale.ROOT); + if (i == propParts.length - 1) { + // suggest for next property + String previous = Arrays.stream(propParts, 0, propParts.length - 1).collect(Collectors.joining(",")) + + (propParts.length == 1 ? "" : ","); + String lastValidInput = (blockType + "[" + previous).toLowerCase(Locale.ROOT); + if (propVal.length == 1) { + // only property, no value yet + final List> matchingProps = propertyMap.entrySet().stream() + .filter(p -> !matchedProperties.contains(p.getKey()) && p.getKey().startsWith(matchProp)) + .map(Map.Entry::getValue).collect(Collectors.toList()); + switch (matchingProps.size()) { + case 0: + return propertyMap.keySet().stream().filter(p -> !matchedProperties.contains(p)).map(prop -> + lastValidInput + prop + "="); + case 1: + return matchingProps.get(0).getValues().stream().map(val -> + lastValidInput + matchingProps.get(0).getName() + "=" + + val.toString().toLowerCase(Locale.ROOT)); + default: + return matchingProps.stream().map(p -> lastValidInput + p.getName() + "="); + } + } else { + Property prop = propertyMap.get(matchProp); + if (prop == null) { + return propertyMap.keySet().stream().map(p -> lastValidInput + p); + } + final List values = prop.getValues().stream().map(v -> v.toString().toLowerCase(Locale.ROOT)).collect(Collectors.toList()); + String matchVal = propVal[1].toLowerCase(Locale.ROOT); + List matchingVals = values.stream().filter(val -> val.startsWith(matchVal)).collect(Collectors.toList()); + if (matchingVals.isEmpty()) { + return values.stream().map(val -> lastValidInput + prop.getName() + "=" + val); + } else { + if (matchingVals.size() == 1 && matchingVals.get(0).equals(matchVal)) { + String currProp = lastValidInput + prop.getName() + "=" + matchVal; + if (matchingVals.size() < values.size()) { + return Stream.of(currProp + "] ", currProp + ","); + } + return Stream.of(currProp + "] "); + } + return matchingVals.stream().map(val -> lastValidInput + prop.getName() + "=" + val); + } + } + } else { + // validate previous properties + if (propVal.length != 2) { + return Stream.empty(); + } + Property prop = propertyMap.get(matchProp); + if (prop == null) { + return Stream.empty(); + } + try { + prop.getValueFor(propVal[1]); + matchedProperties.add(prop.getName()); + } catch (IllegalArgumentException ignored) { + return Stream.empty(); + } + } + } + return Stream.empty(); + } + + public static Stream getRegistrySuggestions(Registry registry, String input) { + if (registry instanceof NamespacedRegistry) { + return getNamespacedRegistrySuggestions(((NamespacedRegistry) registry), input); + } + return limitByPrefix(registry.keySet().stream(), input).stream(); + } + + public static Stream getNamespacedRegistrySuggestions(NamespacedRegistry registry, String input) { + if (input.isEmpty() || input.equals(":")) { + final Set namespaces = registry.getKnownNamespaces(); + if (namespaces.size() == 1) { + int def = namespaces.iterator().next().length() + 1; // default namespace length + ':' + return registry.keySet().stream().map(s -> s.substring(def)); + } else { + return namespaces.stream().map(s -> s + ":"); + } + } + if (input.startsWith(":")) { // special case - search across namespaces + final String term = input.substring(1).toLowerCase(Locale.ROOT); + Predicate search = byPrefix(term); + return registry.keySet().stream().filter(s -> search.test(s.substring(s.indexOf(':') + 1))); + } + // otherwise, we actually have some text to search + if (input.indexOf(':') < 0) { + // don't yet have namespace - search namespaces + default + final String lowerSearch = input.toLowerCase(Locale.ROOT); + String defKey = registry.getDefaultNamespace() + ":" + lowerSearch; + int defLength = registry.getDefaultNamespace().length() + 1; + return Stream.concat(registry.keySet().stream().filter(s -> s.startsWith(defKey)).map(s -> s.substring(defLength)), + registry.getKnownNamespaces().stream().filter(n -> n.startsWith(lowerSearch)).map(n -> n + ":")); + } + // have a namespace - search that + Predicate search = byPrefix(input.toLowerCase(Locale.ROOT)); + return registry.keySet().stream().filter(search); + } +} diff --git a/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java b/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java new file mode 100644 index 0000000..be5f5fb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.command.util; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Actor; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; + +import java.util.concurrent.Callable; +import javax.annotation.Nullable; + +/** + * For internal WorldEdit use only. + */ +public final class WorldEditAsyncCommandBuilder { + private WorldEditAsyncCommandBuilder() { + } + + @Deprecated + public static void createAndSendMessage(Actor actor, Callable task, @Nullable String desc) { + createAndSendMessage(actor, task, desc != null ? TextComponent.of(desc) : null); + } + + public static void createAndSendMessage(Actor actor, Callable task, @Nullable Component desc) { + final AsyncCommandBuilder builder = AsyncCommandBuilder.wrap(task, actor); + if (desc != null) { + builder.setDelayMessage(desc); + } + builder + .onSuccess((String) null, actor::printInfo) + .onFailure((String) null, WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter()) + .buildAndExec(WorldEdit.getInstance().getExecutorService()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java b/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java new file mode 100644 index 0000000..410569b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java @@ -0,0 +1,104 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.entity; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.NbtValued; +import com.sk89q.worldedit.world.entity.EntityType; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a mutable "snapshot" of an entity. + * + *

An instance of this class contains all the information needed to + * accurately reproduce the entity, provided that the instance was + * made correctly. In some implementations, it may not be possible to get a + * snapshot of entities correctly, so, for example, the NBT data for an entity + * may be missing.

+ * + *

This class identifies entities using its entity type string, although + * this is not very efficient as the types are currently not interned. This + * may be changed in the future.

+ */ +public class BaseEntity implements NbtValued { + + private final EntityType type; + private CompoundTag nbtData; + + /** + * Create a new base entity. + * + * @param type the entity type + * @param nbtData NBT data + */ + public BaseEntity(EntityType type, CompoundTag nbtData) { + this(type); + setNbtData(nbtData); + } + + /** + * Create a new base entity with no NBT data. + * + * @param type the entity type + */ + public BaseEntity(EntityType type) { + this.type = type; + } + + /** + * Make a clone of a {@link BaseEntity}. + * + * @param other the object to clone + */ + public BaseEntity(BaseEntity other) { + checkNotNull(other); + this.type = other.getType(); + setNbtData(other.getNbtData()); + } + + @Override + public boolean hasNbtData() { + return nbtData != null; + } + + @Nullable + @Override + public CompoundTag getNbtData() { + return nbtData; + } + + @Override + public void setNbtData(@Nullable CompoundTag nbtData) { + this.nbtData = nbtData; + } + + /** + * Get the type of entity. + * + * @return the entity type + */ + public EntityType getType() { + return this.type; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/entity/Entity.java b/src/main/java/com/sk89q/worldedit/entity/Entity.java new file mode 100644 index 0000000..ffa5dfd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/entity/Entity.java @@ -0,0 +1,57 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.entity; + +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Faceted; + +import javax.annotation.Nullable; + +/** + * A reference to an instance of an entity that exists in an {@link Extent} + * and thus would have position and similar details. + * + *

This object cannot be directly cloned because it represents a particular + * instance of an entity, but a {@link BaseEntity} can be created from + * this entity by calling {@link #getState()}.

+ */ +public interface Entity extends Faceted, Locatable { + + /** + * Get a copy of the entity's state. + * + *

In some cases, this method may return {@code null} if a snapshot + * of the entity can't be created. It may not be possible, for example, + * to get a snapshot of a player.

+ * + * @return the entity's state or null if one cannot be created + */ + @Nullable + BaseEntity getState(); + + /** + * Remove this entity from it container. + * + * @return true if removal was successful + */ + boolean remove(); + +} diff --git a/src/main/java/com/sk89q/worldedit/entity/Player.java b/src/main/java/com/sk89q/worldedit/entity/Player.java new file mode 100644 index 0000000..da435da --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -0,0 +1,332 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.entity; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.gamemode.GameMode; + +import javax.annotation.Nullable; + +/** + * Represents a player. + */ +public interface Player extends Entity, Actor { + + /** + * Return the world that the player is on. + * + * @return the world + */ + World getWorld(); + + /** + * Returns true if the entity is holding a pick axe. + * + * @return whether a pick axe is held + */ + boolean isHoldingPickAxe(); + + /** + * Get the player's cardinal direction (N, W, NW, etc.) with an offset. May return null. + * @param yawOffset offset that is added to the player's yaw before determining the cardinal direction + * + * @return the direction + */ + Direction getCardinalDirection(int yawOffset); + + /** + * Get the item that the player is holding. + * + * @return the item the player is holding + */ + BaseItemStack getItemInHand(HandSide handSide); + + /** + * Get the Block that the player is holding. + * + * @return the item id of the item the player is holding + */ + BaseBlock getBlockInHand(HandSide handSide) throws WorldEditException; + + /** + * Gives the player an item. + * + * @param itemStack The item to give + */ + void giveItem(BaseItemStack itemStack); + + /** + * Get this actor's block bag. + * + * @return the actor's block bag + */ + BlockBag getInventoryBlockBag(); + + /** + * Return this actor's game mode. + * + * @return the game mode + */ + GameMode getGameMode(); + + /** + * Sets the player to the given game mode. + * + * @param gameMode The game mode + */ + void setGameMode(GameMode gameMode); + + /** + * Find a position for the actor to stand that is not inside a block. + * Blocks above the player will be iteratively tested until there is + * a series of two free blocks. The actor will be teleported to + * that free position. + * + * @param searchPos search position + */ + void findFreePosition(Location searchPos); + + /** + * Set the actor on the ground. + * + * @param searchPos The location to start searching from + */ + void setOnGround(Location searchPos); + + /** + * Find a position for the player to stand that is not inside a block. + * Blocks above the player will be iteratively tested until there is + * a series of two free blocks. The player will be teleported to + * that free position. + */ + void findFreePosition(); + + /** + * Go up one level to the next free space above. + * + * @return true if a spot was found + */ + boolean ascendLevel(); + + /** + * Go up one level to the next free space above. + * + * @return true if a spot was found + */ + boolean descendLevel(); + + /** + * Ascend to the ceiling above. + * + * @param clearance How many blocks to leave above the player's head + * @return whether the player was moved + */ + boolean ascendToCeiling(int clearance); + + /** + * Ascend to the ceiling above. + * + * @param clearance How many blocks to leave above the player's head + * @param alwaysGlass Always put glass under the player + * @return whether the player was moved + */ + boolean ascendToCeiling(int clearance, boolean alwaysGlass); + + /** + * Just go up. + * + * @param distance How far up to teleport + * @return whether the player was moved + */ + boolean ascendUpwards(int distance); + + /** + * Just go up. + * + * @param distance How far up to teleport + * @param alwaysGlass Always put glass under the player + * @return whether the player was moved + */ + boolean ascendUpwards(int distance, boolean alwaysGlass); + + /** + * Make the player float in the given blocks. + * + * @param x The X coordinate of the block to float in + * @param y The Y coordinate of the block to float in + * @param z The Z coordinate of the block to float in + */ + void floatAt(int x, int y, int z, boolean alwaysGlass); + + /** + * Get the point of the block that is being stood in. + * + * @return point + * @deprecated Use Locatable#getBlockLocation + */ + @Deprecated + default Location getBlockIn() { + return getBlockLocation(); + } + + /** + * Get the point of the block that is being stood upon. + * + * @return point + */ + Location getBlockOn(); + + /** + * Get the point of the block being looked at. May return null. + * Will return the farthest away air block if useLastBlock is true and no other block is found. + * + * @param range how far to checks for blocks + * @param useLastBlock try to return the last valid air block found + * @return point + */ + Location getBlockTrace(int range, boolean useLastBlock); + + /** + * Get the point of the block being looked at. May return null. + * Will return the farthest away block before matching the stop mask if useLastBlock is true and no other block is found. + * + * @param range how far to checks for blocks + * @param useLastBlock try to return the last valid block not matching the stop mask found + * @param stopMask the mask used to determine when to stop tracing + * @return point + */ + Location getBlockTrace(int range, boolean useLastBlock, @Nullable Mask stopMask); + + /** + * Get the face that the player is looking at. + * + * @param range the range + * @param useLastBlock try to return the last valid air block found + * @return a face + */ + Location getBlockTraceFace(int range, boolean useLastBlock); + + /** + * Get the face that the player is looking at. + * + * @param range the range + * @param useLastBlock try to return the last valid block not matching the stop mask found + * @param stopMask the mask used to determine when to stop tracing + * @return a face + */ + Location getBlockTraceFace(int range, boolean useLastBlock, @Nullable Mask stopMask); + + /** + * Get the point of the block being looked at. May return null. + * + * @param range How far to checks for blocks + * @return point + */ + Location getBlockTrace(int range); + + /** + * Get the point of the block being looked at. May return null. + * + * @param range How far to checks for blocks + * @return point + */ + Location getSolidBlockTrace(int range); + + /** + * Get the player's cardinal direction (N, W, NW, etc.). May return null. + * + * @return the direction + */ + Direction getCardinalDirection(); + + /** + * Pass through the wall that you are looking at. + * + * @param range How far to checks for blocks + * @return whether the player was pass through + */ + boolean passThroughForwardWall(int range); + + /** + * Move the player. + * + * @param pos where to move them + * @param pitch the pitch (up/down) of the player's view in degrees + * @param yaw the yaw (left/right) of the player's view in degrees + * @deprecated This method may fail without indication. Use {@link #trySetPosition(Vector3, float, float)} instead + */ + @Deprecated + default void setPosition(Vector3 pos, float pitch, float yaw) { + trySetPosition(pos, pitch, yaw); + } + + /** + * Attempt to move the player. + * + *

+ * This action may fail, due to other mods cancelling the move. + * If so, this method will return {@code false}. + *

+ * + * @param pos where to move them + * @param pitch the pitch (up/down) of the player's view in degrees + * @param yaw the yaw (left/right) of the player's view in degrees + * @return if the move was able to occur + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "setPosition", + delegateParams = { Vector3.class, float.class, float.class } + ) + default boolean trySetPosition(Vector3 pos, float pitch, float yaw) { + DeprecationUtil.checkDelegatingOverride(getClass()); + + setPosition(pos, pitch, yaw); + + return true; + } + + /** + * Sends a fake block to the client. + * + *

+ * This block isn't real. + *

+ * + * @param pos The position of the block + * @param block The block to send, null to reset + */ + > void sendFakeBlock(BlockVector3 pos, @Nullable B block); +} diff --git a/src/main/java/com/sk89q/worldedit/entity/metadata/EntityProperties.java b/src/main/java/com/sk89q/worldedit/entity/metadata/EntityProperties.java new file mode 100644 index 0000000..eae08e3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/entity/metadata/EntityProperties.java @@ -0,0 +1,171 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.entity.metadata; + +/** + * Describes various classes of entities. + */ +public interface EntityProperties { + + /** + * Test whether the entity is a player-derived entity. + * + * @return true if a player derived entity + */ + boolean isPlayerDerived(); + + /** + * Test whether the entity is a projectile. + * + * @return true if a projectile + */ + boolean isProjectile(); + + /** + * Test whether the entity is an item. + * + * @return true if an item + */ + boolean isItem(); + + /** + * Test whether the entity is a falling block. + * + * @return true if a falling block + */ + boolean isFallingBlock(); + + /** + * Test whether the entity is a painting. + * + * @return true if a painting + */ + boolean isPainting(); + + /** + * Test whether the entity is an item frame. + * + * @return true if an item frame + */ + boolean isItemFrame(); + + /** + * Test whether the entity is a boat. + * + * @return true if a boat + */ + boolean isBoat(); + + /** + * Test whether the entity is a minecart. + * + * @return true if a minecart + */ + boolean isMinecart(); + + /** + * Test whether the entity is a primed TNT block. + * + * @return true if TNT + */ + boolean isTNT(); + + /** + * Test whether the entity is an experience orb. + * + * @return true if an experience orb + */ + boolean isExperienceOrb(); + + /** + * Test whether the entity is a living entity. + * + *

A "living entity" is the superclass of many living entity classes + * in Minecraft.

+ * + * @return true if a living entity + */ + boolean isLiving(); + + /** + * Test whether the entity is an animal. + * + * @return true if an animal + */ + boolean isAnimal(); + + /** + * Test whether the entity is an ambient creature, which includes + * the bat. + * + * @return true if an ambient creature + */ + boolean isAmbient(); + + /** + * Test whether the entity is a non-player controlled character, which + * includes villagers, NPCs from mods, and so on. + * + * @return true if an NPC + */ + boolean isNPC(); + + /** + * Test whether the entity is the iron golem from Minecraft. + * + * @return true if an iron golem + */ + boolean isGolem(); + + /** + * Test whether the entity is tameable and is tamed. + * + * @return true if tamed + */ + boolean isTamed(); + + /** + * Test whether the entity has been named (tagged). + * + * @return true if named + */ + boolean isTagged(); + + /** + * Test whether the entity is an armor stand. + * + * @return true if an armor stand + */ + boolean isArmorStand(); + + /** + * Test whether this entity can be pasted. + * + * @return true if pasteable + */ + boolean isPasteable(); + + /** + * Test whether the entity is a water creature. + * + * @return true if water creature + */ + boolean isWaterCreature(); +} diff --git a/src/main/java/com/sk89q/worldedit/event/AbstractCancellable.java b/src/main/java/com/sk89q/worldedit/event/AbstractCancellable.java new file mode 100644 index 0000000..a40ad6c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/AbstractCancellable.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event; + +/** + * An abstract implementation of {@link Cancellable} that has all + * of {@link Cancellable}'s methods implemented. + */ +public abstract class AbstractCancellable implements Cancellable { + + private boolean cancelled; + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } +} diff --git a/src/main/java/com/sk89q/worldedit/event/Cancellable.java b/src/main/java/com/sk89q/worldedit/event/Cancellable.java new file mode 100644 index 0000000..8795f4d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/Cancellable.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event; + +/** + * Marks an event that has a cancellable state. The meaning of cancellation + * depends on the event. + */ +public interface Cancellable { + + /** + * Returns whether the event has been cancelled. + * + * @return true if cancelled + */ + boolean isCancelled(); + + /** + * Set whether the event has been cancelled. + * + * @param cancelled true if cancelled + */ + void setCancelled(boolean cancelled); + +} diff --git a/src/main/java/com/sk89q/worldedit/event/Event.java b/src/main/java/com/sk89q/worldedit/event/Event.java new file mode 100644 index 0000000..c0d351a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/Event.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event; + +/** + * An abstract base class for all WorldEdit events. + */ +public abstract class Event { +} diff --git a/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java b/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java new file mode 100644 index 0000000..3b1904b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java @@ -0,0 +1,180 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.extent; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.event.Event; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.TracingExtent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.EditSession.Stage; + +/** + * Raised (several times) when a new {@link EditSession} is being instantiated. + * + *

Block loggers, as well as block set interceptors, can use this event to wrap + * the given {@link Extent} with their own, which would allow them to intercept + * all changes made to the world. For example, the code below would wrap the + * existing extent with a custom one, and the custom extent would receive + * all method calls before the extent fetched from + * {@link #getExtent()} would.

+ * + *
+ * event.setExtent(new MyExtent(event.getExtent())
+ * 
+ * + *

This event is fired several times during the creation of a single + * {@link EditSession}, but {@link #getStage()} will differ each time. + * The stage determines at which point {@link Extent}s added to this event + * will be called. For example, if you inject an extent when the stage + * is set to {@link Stage#BEFORE_HISTORY}, then you can drop (or log) changes + * before the change has reached the history, reordering, and actual change + * extents, but that means that any changes made with + * {@link EditSession#rawSetBlock(BlockVector3, BlockStateHolder)} will skip your + * custom {@link Extent} because that method bypasses history (and reorder). + * It is thus recommended that loggers intercept at {@link Stage#BEFORE_CHANGE} + * and block interceptors intercept at BOTH {@link Stage#BEFORE_CHANGE} and + * {@link Stage#BEFORE_HISTORY}.

+ */ +public class EditSessionEvent extends Event { + + private final World world; + private final Actor actor; + private final int maxBlocks; + private final Stage stage; + private final List tracingExtents = new ArrayList<>(); + private Extent extent; + private boolean tracing; + + /** + * Create a new event. + * + * @param world the world + * @param actor the actor, or null if there is no actor specified + * @param maxBlocks the maximum number of block changes + * @param stage the stage + */ + public EditSessionEvent(@Nullable World world, Actor actor, int maxBlocks, Stage stage) { + this.world = world; + this.actor = actor; + this.maxBlocks = maxBlocks; + this.stage = stage; + } + + /** + * Get the actor for this event. + * + * @return the actor, which may be null if unavailable + */ + public @Nullable Actor getActor() { + return actor; + } + + /** + * Get the world. + * + * @return the world + */ + public @Nullable World getWorld() { + return world; + } + + /** + * Get the maximum number of blocks that may be set. + * + * @return the maximum number of blocks, which is -1 if unlimited + */ + public int getMaxBlocks() { + return maxBlocks; + } + + /** + * Get the {@link Extent} that can be wrapped. + * + * @return the extent + */ + public Extent getExtent() { + return extent; + } + + /** + * Get the stage that is being wrapped. + * + * @return the stage + */ + public Stage getStage() { + return stage; + } + + /** + * Set a new extent that should be used. It should wrap the extent + * returned from {@link #getExtent()}. + * + * @param extent the extent + */ + public void setExtent(Extent extent) { + checkNotNull(extent); + if (tracing && extent != this.extent) { + TracingExtent tracingExtent = new TracingExtent(extent); + extent = tracingExtent; + tracingExtents.add(tracingExtent); + } + this.extent = extent; + } + + /** + * Set tracing enabled, with the current extent as the "base". + * + * Internal use only. + * @param tracing if tracing is enabled + */ + public void setTracing(boolean tracing) { + this.tracing = tracing; + } + + /** + * Get the current list of tracing extents. + * + * Internal use only. + */ + public List getTracingExtents() { + return tracingExtents; + } + + /** + * Create a clone of this event with the given stage. + * + * @param stage the stage + * @return a new event + */ + public EditSessionEvent clone(Stage stage) { + return new EditSessionEvent(world, actor, maxBlocks, stage); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/BlockInteractEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/BlockInteractEvent.java new file mode 100644 index 0000000..a7db9b2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/BlockInteractEvent.java @@ -0,0 +1,119 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.event.Cancellable; +import com.sk89q.worldedit.event.Event; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Called when a block is interacted with. + */ +public class BlockInteractEvent extends Event implements Cancellable { + + private final Actor cause; + private final Location location; + private final Interaction type; + private final Direction face; + private boolean cancelled; + + /** + * Create a new event. + * + * @param cause the causing actor + * @param location the location of the block + * @param type the type of interaction + */ + @Deprecated + public BlockInteractEvent(Actor cause, Location location, Interaction type) { + this(cause, location, null, type); + } + + /** + * Create a new event. + * + * @param cause the causing actor + * @param location the location of the block + * @param face the face of the block that was interacted with + * @param type the type of interaction + */ + public BlockInteractEvent(Actor cause, Location location, @Nullable Direction face, Interaction type) { + checkNotNull(cause); + checkNotNull(location); + checkNotNull(type); + this.cause = cause; + this.location = location; + this.face = face; + this.type = type; + } + + /** + * Get the cause of this event. + * + * @return the cause + */ + public Actor getCause() { + return cause; + } + + /** + * Get the location of the block that was interacted with. + * + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * Get the face of the block that was interacted with. + * + * @return The interacted face + */ + @Nullable + public Direction getFace() { + return face; + } + + /** + * Get the type of interaction. + * + * @return the type of interaction + */ + public Interaction getType() { + return type; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/CommandEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/CommandEvent.java new file mode 100644 index 0000000..51a11fa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/CommandEvent.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.event.AbstractCancellable; +import com.sk89q.worldedit.extension.platform.Actor; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * This class is currently only for internal use. Do not post or catch this event. + */ +public class CommandEvent extends AbstractCancellable { + + private final Actor actor; + private final String arguments; + + /** + * Create a new instance. + * + * @param actor the player + * @param arguments the arguments + */ + public CommandEvent(Actor actor, String arguments) { + checkNotNull(actor); + checkNotNull(arguments); + + this.actor = actor; + this.arguments = arguments; + } + + /** + * Get the actor that issued the command. + * + * @return the actor that issued the command + */ + public Actor getActor() { + return actor; + } + + /** + * Get the arguments. + * + * @return the arguments + */ + public String getArguments() { + return arguments; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java new file mode 100644 index 0000000..6e1c92c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java @@ -0,0 +1,96 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.event.Event; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.util.Substring; + +import java.util.Collections; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Posted when suggestions for auto-completion are requested for command input. + */ +public class CommandSuggestionEvent extends Event { + + private final Actor actor; + private final String arguments; + private List suggestions = Collections.emptyList(); + + /** + * Create a new instance. + * + * @param actor the player + * @param arguments the arguments + */ + public CommandSuggestionEvent(Actor actor, String arguments) { + checkNotNull(actor); + checkNotNull(arguments); + + this.actor = actor; + this.arguments = arguments; + } + + /** + * Get the actor that issued the command. + * + * @return the actor that issued the command + */ + public Actor getActor() { + return actor; + } + + /** + * Get the arguments. + * + * @return the arguments + */ + public String getArguments() { + return arguments; + } + + /** + * Get the list of suggestions that are to be presented. + * + *

+ * Each Substring holds the replacement as the substring, + * and the replacement range as the original substring range. + *

+ * + * @return the list of suggestions + */ + public List getSuggestions() { + return suggestions; + } + + /** + * Set the list of suggestions that are to be presented. + * + * @param suggestions the list of suggestions + */ + public void setSuggestions(List suggestions) { + checkNotNull(suggestions); + this.suggestions = suggestions; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/ConfigurationLoadEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/ConfigurationLoadEvent.java new file mode 100644 index 0000000..d4ae747 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/ConfigurationLoadEvent.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.event.Event; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Raised when the configuration has been loaded or re-loaded. + */ +public class ConfigurationLoadEvent extends Event { + + private final LocalConfiguration configuration; + + /** + * Create a new instance. + * + * @param configuration the new configuration + */ + public ConfigurationLoadEvent(LocalConfiguration configuration) { + checkNotNull(configuration); + this.configuration = configuration; + } + + /** + * Get the configuration. + * + * @return the configuration + */ + public LocalConfiguration getConfiguration() { + return configuration; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/InputType.java b/src/main/java/com/sk89q/worldedit/event/platform/InputType.java new file mode 100644 index 0000000..3c4c4cb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/InputType.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +/** + * The type of input sent. + */ +public enum InputType { + + /** + * Left click. + */ + PRIMARY, + + /** + * Right click. + */ + SECONDARY + +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/Interaction.java b/src/main/java/com/sk89q/worldedit/event/platform/Interaction.java new file mode 100644 index 0000000..1f93b97 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/Interaction.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +/** + * The type of interaction. + */ +public enum Interaction { + + /** + * Refers to primary input usage (left click). + */ + HIT, + + /** + * Refers to secondary input usage (right click). + */ + OPEN + +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/PlatformEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/PlatformEvent.java new file mode 100644 index 0000000..261b78a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/PlatformEvent.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.event.Event; +import com.sk89q.worldedit.extension.platform.Platform; + +public abstract class PlatformEvent extends Event { + private final Platform platform; + + protected PlatformEvent(Platform platform) { + this.platform = platform; + } + + /** + * Get the platform for this event. + * + * @return the platform + */ + public Platform getPlatform() { + return platform; + } +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/PlatformInitializeEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/PlatformInitializeEvent.java new file mode 100644 index 0000000..8b89201 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/PlatformInitializeEvent.java @@ -0,0 +1,31 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.event.Event; + +/** + * Fired when configuration has been loaded and the platform is in the + * intialization stage. + * + *

This event is fired once.

+ */ +public class PlatformInitializeEvent extends Event { +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/PlatformReadyEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/PlatformReadyEvent.java new file mode 100644 index 0000000..7ae072a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/PlatformReadyEvent.java @@ -0,0 +1,31 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.extension.platform.Platform; + +/** + * Raised when a platform has finished loading its data. + */ +public class PlatformReadyEvent extends PlatformEvent { + public PlatformReadyEvent(Platform platform) { + super(platform); + } +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/PlatformUnreadyEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/PlatformUnreadyEvent.java new file mode 100644 index 0000000..25930e6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/PlatformUnreadyEvent.java @@ -0,0 +1,31 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.extension.platform.Platform; + +/** + * Raised when a platform needs to retract all registered data, e.g. due to a reload. + */ +public class PlatformUnreadyEvent extends PlatformEvent { + public PlatformUnreadyEvent(Platform platform) { + super(platform); + } +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/PlatformsRegisteredEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/PlatformsRegisteredEvent.java new file mode 100644 index 0000000..8eac256 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/PlatformsRegisteredEvent.java @@ -0,0 +1,28 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.event.Event; + +/** + * Fired by a platform when it believes all available platforms should be registered. + */ +public class PlatformsRegisteredEvent extends Event { +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/PlayerInputEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/PlayerInputEvent.java new file mode 100644 index 0000000..57b816a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/PlayerInputEvent.java @@ -0,0 +1,78 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.event.Cancellable; +import com.sk89q.worldedit.event.Event; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Raised whenever a player sends input. + */ +public class PlayerInputEvent extends Event implements Cancellable { + + private final Player player; + private final InputType inputType; + private boolean cancelled; + + /** + * Create a new event. + * + * @param player the player + * @param inputType the input type + */ + public PlayerInputEvent(Player player, InputType inputType) { + checkNotNull(player); + checkNotNull(inputType); + this.player = player; + this.inputType = inputType; + } + + /** + * Get the player that sent the input. + * + * @return the player + */ + public Player getPlayer() { + return player; + } + + /** + * Get the type of input sent. + * + * @return the input sent + */ + public InputType getInputType() { + return inputType; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/event/platform/SessionIdleEvent.java b/src/main/java/com/sk89q/worldedit/event/platform/SessionIdleEvent.java new file mode 100644 index 0000000..a304d0b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/platform/SessionIdleEvent.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.event.platform; + +import com.sk89q.worldedit.event.Event; +import com.sk89q.worldedit.session.SessionKey; + +/** + * An event fired when a session becomes idle. + * + *

This can happen when a player leaves the server.

+ */ +public final class SessionIdleEvent extends Event { + private final SessionKey key; + + public SessionIdleEvent(SessionKey key) { + this.key = key; + } + + /** + * Get a key identifying the session that has become idle. + * + * @return the key for the session + */ + public SessionKey getKey() { + return this.key; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java b/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java new file mode 100644 index 0000000..aeaa109 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory; + +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.factory.parser.DefaultBlockParser; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.internal.registry.AbstractFactory; +import com.sk89q.worldedit.world.block.BaseBlock; + +import java.util.HashSet; +import java.util.Set; + +/** + * A registry of known {@link BaseBlock}s. Provides methods to instantiate + * new blocks from input. + * + *

Instances of this class can be taken from + * {@link WorldEdit#getBlockFactory()}.

+ */ +public class BlockFactory extends AbstractFactory { + + /** + * Create a new instance. + * + * @param worldEdit the WorldEdit instance. + */ + public BlockFactory(WorldEdit worldEdit) { + super(worldEdit, new DefaultBlockParser(worldEdit)); + } + + /** + * Return a set of blocks from a comma-delimited list of blocks. + * + * @param input the input + * @param context the context + * @return a set of blocks + * @throws InputParseException thrown in error with the input + */ + public Set parseFromListInput(String input, ParserContext context) throws InputParseException { + Set blocks = new HashSet<>(); + String[] splits = input.split(","); + for (String token : StringUtil.parseListInQuotes(splits, ',', '[', ']', true)) { + blocks.add(parseFromInput(token, context)); + } + return blocks; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java b/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java new file mode 100644 index 0000000..b1858a1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java @@ -0,0 +1,38 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.extension.factory.parser.DefaultItemParser; +import com.sk89q.worldedit.internal.registry.AbstractFactory; + +public class ItemFactory extends AbstractFactory { + + /** + * Create a new instance. + * + * @param worldEdit the WorldEdit instance. + */ + public ItemFactory(WorldEdit worldEdit) { + super(worldEdit, new DefaultItemParser(worldEdit)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java b/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java new file mode 100644 index 0000000..f07f686 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java @@ -0,0 +1,129 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.factory.parser.mask.AirMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.BiomeMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.BlockCategoryMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.BlockStateMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.BlocksMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.ExistingMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.ExposedMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.ExpressionMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.LazyRegionMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.NegateMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.NoiseMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.OffsetMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.RegionMaskParser; +import com.sk89q.worldedit.extension.factory.parser.mask.SolidMaskParser; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.MaskIntersection; +import com.sk89q.worldedit.internal.registry.AbstractFactory; +import com.sk89q.worldedit.internal.registry.InputParser; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * A registry of known {@link Mask}s. Provides methods to instantiate + * new masks from input. + * + *

Instances of this class can be taken from + * {@link WorldEdit#getMaskFactory()}.

+ */ +public final class MaskFactory extends AbstractFactory { + + /** + * Create a new mask registry. + * + * @param worldEdit the WorldEdit instance + */ + public MaskFactory(WorldEdit worldEdit) { + super(worldEdit, new BlocksMaskParser(worldEdit)); + + register(new ExistingMaskParser(worldEdit)); + register(new AirMaskParser(worldEdit)); + register(new ExposedMaskParser(worldEdit)); + register(new SolidMaskParser(worldEdit)); + register(new LazyRegionMaskParser(worldEdit)); + register(new RegionMaskParser(worldEdit)); + register(new OffsetMaskParser(worldEdit)); + register(new NoiseMaskParser(worldEdit)); + register(new BlockStateMaskParser(worldEdit)); + register(new NegateMaskParser(worldEdit)); + register(new ExpressionMaskParser(worldEdit)); + + register(new BlockCategoryMaskParser(worldEdit)); + register(new BiomeMaskParser(worldEdit)); + } + + @Override + public List getSuggestions(String input) { + final String[] split = input.split(" "); + if (split.length > 1) { + String prev = input.substring(0, input.lastIndexOf(" ")) + " "; + return super.getSuggestions(split[split.length - 1]).stream() + .map(s -> prev + s) + .collect(Collectors.toList()); + } + return super.getSuggestions(input); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + List masks = new ArrayList<>(); + + for (String component : input.split(" ")) { + if (component.isEmpty()) { + continue; + } + + Mask match = null; + for (InputParser parser : getParsers()) { + match = parser.parseFromInput(component, context); + + if (match != null) { + break; + } + } + if (match == null) { + throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(component))); + } + masks.add(match); + } + + switch (masks.size()) { + case 0: + throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(input))); + case 1: + return masks.get(0); + default: + return new MaskIntersection(masks); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java b/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java new file mode 100644 index 0000000..8c3a32c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java @@ -0,0 +1,54 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.factory.parser.pattern.*; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.registry.AbstractFactory; + +/** + * A registry of known {@link Pattern}s. Provides methods to instantiate + * new patterns from input. + * + *

Instances of this class can be taken from + * {@link WorldEdit#getPatternFactory()}.

+ */ +public final class PatternFactory extends AbstractFactory { + + /** + * Create a new instance. + * + * @param worldEdit the WorldEdit instance + */ + public PatternFactory(WorldEdit worldEdit) { + super(worldEdit, new SingleBlockPatternParser(worldEdit)); + + // split and parse each sub-pattern + register(new RandomPatternParser(worldEdit)); + + // individual patterns + register(new ClipboardPatternParser(worldEdit)); + register(new TypeOrStateApplyingPatternParser(worldEdit)); + register(new RandomStatePatternParser(worldEdit)); + register(new BlockCategoryPatternParser(worldEdit)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java new file mode 100644 index 0000000..4f4f970 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java @@ -0,0 +1,419 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser; + +import com.google.common.collect.Maps; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.NotABlockException; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.MobSpawnerBlock; +import com.sk89q.worldedit.blocks.SignBlock; +import com.sk89q.worldedit.blocks.SkullBlock; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.input.DisallowedUsageException; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.HandSide; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.block.FuzzyBlockState; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.registry.LegacyMapper; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Stream; + +/** + * Parses block input strings. + */ +public class DefaultBlockParser extends InputParser { + + public DefaultBlockParser(WorldEdit worldEdit) { + super(worldEdit); + } + + private static BaseBlock getBlockInHand(Actor actor, HandSide handSide) throws InputParseException { + if (actor instanceof Player) { + try { + return ((Player) actor).getBlockInHand(handSide); + } catch (NotABlockException e) { + throw new InputParseException(e.getRichMessage()); + } catch (WorldEditException e) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.unknown", e.getRichMessage()), e); + } + } else { + throw new InputParseException(TranslatableComponent.of( + "worldedit.error.parser.player-only", + TextComponent.of(handSide == HandSide.MAIN_HAND ? "hand" : "offhand") + )); + } + } + + @Override + public BaseBlock parseFromInput(String input, ParserContext context) + throws InputParseException { + String originalInput = input; + input = input.replace(";", "|"); + Exception suppressed = null; + try { + BaseBlock modified = parseLogic(input, context); + if (modified != null) { + return modified; + } + } catch (Exception e) { + suppressed = e; + } + try { + return parseLogic(originalInput, context); + } catch (Exception e) { + if (suppressed != null) { + e.addSuppressed(suppressed); + } + throw e; + } + } + + private static final String[] EMPTY_STRING_ARRAY = {}; + + /** + * Backwards compatibility for wool colours in block syntax. + * + * @param string Input string + * @return Mapped string + */ + @SuppressWarnings("ConstantConditions") + private String woolMapper(String string) { + switch (string.toLowerCase(Locale.ROOT)) { + case "white": + return BlockTypes.WHITE_WOOL.getId(); + case "black": + return BlockTypes.BLACK_WOOL.getId(); + case "blue": + return BlockTypes.BLUE_WOOL.getId(); + case "brown": + return BlockTypes.BROWN_WOOL.getId(); + case "cyan": + return BlockTypes.CYAN_WOOL.getId(); + case "gray": + case "grey": + return BlockTypes.GRAY_WOOL.getId(); + case "green": + return BlockTypes.GREEN_WOOL.getId(); + case "light_blue": + case "lightblue": + return BlockTypes.LIGHT_BLUE_WOOL.getId(); + case "light_gray": + case "light_grey": + case "lightgray": + case "lightgrey": + return BlockTypes.LIGHT_GRAY_WOOL.getId(); + case "lime": + return BlockTypes.LIME_WOOL.getId(); + case "magenta": + return BlockTypes.MAGENTA_WOOL.getId(); + case "orange": + return BlockTypes.ORANGE_WOOL.getId(); + case "pink": + return BlockTypes.PINK_WOOL.getId(); + case "purple": + return BlockTypes.PURPLE_WOOL.getId(); + case "yellow": + return BlockTypes.YELLOW_WOOL.getId(); + case "red": + return BlockTypes.RED_WOOL.getId(); + default: + return string; + } + } + + private static Map, Object> parseProperties(BlockType type, String[] stateProperties, ParserContext context) throws InputParseException { + Map, Object> blockStates = new HashMap<>(); + + if (stateProperties.length > 0) { // Block data not yet detected + // Parse the block data (optional) + for (String parseableData : stateProperties) { + try { + String[] parts = parseableData.split("="); + if (parts.length != 2) { + throw new InputParseException( + TranslatableComponent.of("worldedit.error.parser.bad-state-format", + TextComponent.of(parseableData)) + ); + } + + @SuppressWarnings("unchecked") + Property propertyKey = (Property) type.getPropertyMap().get(parts[0]); + if (propertyKey == null) { + if (context.getActor() != null) { + throw new NoMatchException(TranslatableComponent.of( + "worldedit.error.parser.unknown-property", + TextComponent.of(parts[0]), + TextComponent.of(type.getId()) + )); + } else { + WorldEdit.logger.debug("Unknown property " + parts[0] + " for block " + type.getId()); + } + return Maps.newHashMap(); + } + if (blockStates.containsKey(propertyKey)) { + throw new InputParseException(TranslatableComponent.of( + "worldedit.error.parser.duplicate-property", + TextComponent.of(parts[0]) + )); + } + Object value; + try { + value = propertyKey.getValueFor(parts[1]); + } catch (IllegalArgumentException e) { + throw new NoMatchException(TranslatableComponent.of( + "worldedit.error.parser.unknown-value", + TextComponent.of(parts[1]), + TextComponent.of(propertyKey.getName()) + )); + } + + blockStates.put(propertyKey, value); + } catch (InputParseException e) { + throw e; // Pass-through + } catch (Exception e) { + throw new InputParseException(TranslatableComponent.of( + "worldedit.error.parser.bad-state-format", + TextComponent.of(parseableData) + )); + } + } + } + + return blockStates; + } + + @Override + public Stream getSuggestions(String input) { + final int idx = input.lastIndexOf('['); + if (idx < 0) { + return SuggestionHelper.getNamespacedRegistrySuggestions(BlockType.REGISTRY, input); + } + String blockType = input.substring(0, idx); + BlockType type = BlockTypes.get(blockType.toLowerCase(Locale.ROOT)); + if (type == null) { + return Stream.empty(); + } + + String props = input.substring(idx + 1); + if (props.isEmpty()) { + return type.getProperties().stream().map(p -> input + p.getName() + "="); + } + + return SuggestionHelper.getBlockPropertySuggestions(blockType, props); + } + + private BaseBlock parseLogic(String input, ParserContext context) throws InputParseException { + BlockType blockType = null; + Map, Object> blockStates = new HashMap<>(); + String[] blockAndExtraData = input.trim().split("\\|"); + if (blockAndExtraData.length == 0) { + throw new NoMatchException(TranslatableComponent.of("worldedit.error.unknown-block", TextComponent.of(input))); + } + blockAndExtraData[0] = woolMapper(blockAndExtraData[0]); + + BlockState state = null; + + // Legacy matcher + if (context.isTryingLegacy()) { + try { + String[] split = blockAndExtraData[0].split(":", 2); + if (split.length == 0) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.invalid-colon")); + } else if (split.length == 1) { + state = LegacyMapper.getInstance().getBlockFromLegacy(Integer.parseInt(split[0])); + } else { + state = LegacyMapper.getInstance().getBlockFromLegacy(Integer.parseInt(split[0]), Integer.parseInt(split[1])); + } + if (state != null) { + blockType = state.getBlockType(); + } + } catch (NumberFormatException ignored) { + } + } + + if (state == null) { + String typeString; + String stateString = null; + int stateStart = blockAndExtraData[0].indexOf('['); + if (stateStart == -1) { + typeString = blockAndExtraData[0]; + } else { + typeString = blockAndExtraData[0].substring(0, stateStart); + if (stateStart + 1 >= blockAndExtraData[0].length()) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.hanging-lbracket", TextComponent.of(stateStart))); + } + int stateEnd = blockAndExtraData[0].lastIndexOf(']'); + if (stateEnd < 0) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.missing-rbracket")); + } + stateString = blockAndExtraData[0].substring(stateStart + 1, blockAndExtraData[0].length() - 1); + } + if (typeString.isEmpty()) { + throw new InputParseException(TranslatableComponent.of( + "worldedit.error.parser.bad-state-format", + TextComponent.of(blockAndExtraData[0]) + )); + } + String[] stateProperties = EMPTY_STRING_ARRAY; + if (stateString != null) { + stateProperties = stateString.split(","); + } + + if ("hand".equalsIgnoreCase(typeString)) { + // Get the block type from the item in the user's hand. + final BaseBlock blockInHand = getBlockInHand(context.requireActor(), HandSide.MAIN_HAND); + if (blockInHand.getClass() != BaseBlock.class) { + return blockInHand; + } + + blockType = blockInHand.getBlockType(); + blockStates.putAll(blockInHand.getStates()); + } else if ("offhand".equalsIgnoreCase(typeString)) { + // Get the block type from the item in the user's off hand. + final BaseBlock blockInHand = getBlockInHand(context.requireActor(), HandSide.OFF_HAND); + if (blockInHand.getClass() != BaseBlock.class) { + return blockInHand; + } + + blockType = blockInHand.getBlockType(); + blockStates.putAll(blockInHand.getStates()); + } else if ("pos1".equalsIgnoreCase(typeString)) { + // Get the block type from the "primary position" + final World world = context.requireWorld(); + final BlockVector3 primaryPosition; + try { + primaryPosition = context.requireSession().getRegionSelector(world).getPrimaryPosition(); + } catch (IncompleteRegionException e) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.incomplete-region")); + } + final BlockState blockInHand = world.getBlock(primaryPosition); + + blockType = blockInHand.getBlockType(); + blockStates.putAll(blockInHand.getStates()); + } else { + // Attempt to lookup a block from ID or name. + blockType = BlockTypes.get(typeString.toLowerCase(Locale.ROOT)); + } + + if (blockType == null) { + throw new NoMatchException(TranslatableComponent.of("worldedit.error.unknown-block", TextComponent.of(input))); + } + + blockStates.putAll(parseProperties(blockType, stateProperties, context)); + + if (context.isPreferringWildcard()) { + FuzzyBlockState.Builder fuzzyBuilder = FuzzyBlockState.builder(); + fuzzyBuilder.type(blockType); + for (Map.Entry, Object> blockState : blockStates.entrySet()) { + @SuppressWarnings("unchecked") + Property objProp = (Property) blockState.getKey(); + fuzzyBuilder.withProperty(objProp, blockState.getValue()); + } + state = fuzzyBuilder.build(); + } else { + // No wildcards allowed => eliminate them. (Start with default state) + state = blockType.getDefaultState(); + for (Map.Entry, Object> blockState : blockStates.entrySet()) { + @SuppressWarnings("unchecked") + Property objProp = (Property) blockState.getKey(); + state = state.with(objProp, blockState.getValue()); + } + } + } + // this should be impossible but IntelliJ isn't that smart + if (blockType == null) { + throw new NoMatchException(TranslatableComponent.of("worldedit.error.unknown-block", TextComponent.of(input))); + } + + // Check if the item is allowed + if (context.isRestricted()) { + Actor actor = context.requireActor(); + if (actor != null && !actor.hasPermission("worldedit.anyblock") + && worldEdit.getConfiguration().disallowedBlocks.contains(blockType.getId())) { + throw new DisallowedUsageException(TranslatableComponent.of("worldedit.error.disallowed-block", TextComponent.of(input))); + } + } + + if (!context.isTryingLegacy()) { + return state.toBaseBlock(); + } + + if (DeprecationUtil.isSign(blockType)) { + // Allow special sign text syntax + String[] text = new String[4]; + text[0] = blockAndExtraData.length > 1 ? blockAndExtraData[1] : ""; + text[1] = blockAndExtraData.length > 2 ? blockAndExtraData[2] : ""; + text[2] = blockAndExtraData.length > 3 ? blockAndExtraData[3] : ""; + text[3] = blockAndExtraData.length > 4 ? blockAndExtraData[4] : ""; + return new SignBlock(state, text); + } else if (blockType == BlockTypes.SPAWNER) { + // Allow setting mob spawn type + if (blockAndExtraData.length > 1) { + String mobName = blockAndExtraData[1]; + EntityType ent = EntityTypes.get(mobName.toLowerCase(Locale.ROOT)); + if (ent == null) { + throw new NoMatchException(TranslatableComponent.of("worldedit.error.unknown-entity", TextComponent.of(mobName))); + } + mobName = ent.getId(); + if (!worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).isValidMobType(mobName)) { + throw new NoMatchException(TranslatableComponent.of("worldedit.error.unknown-mob", TextComponent.of(mobName))); + } + return new MobSpawnerBlock(state, mobName); + } else { + //noinspection ConstantConditions + return new MobSpawnerBlock(state, EntityTypes.PIG.getId()); + } + } else if (blockType == BlockTypes.PLAYER_HEAD || blockType == BlockTypes.PLAYER_WALL_HEAD) { + // allow setting type/player/rotation + if (blockAndExtraData.length <= 1) { + return new SkullBlock(state); + } + + String type = blockAndExtraData[1]; + + return new SkullBlock(state, type.replace(" ", "_")); // valid MC usernames + } else { + return state.toBaseBlock(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java new file mode 100644 index 0000000..0c367d1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java @@ -0,0 +1,106 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.util.HandSide; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; +import com.sk89q.worldedit.world.registry.LegacyMapper; + +import java.util.Locale; +import java.util.stream.Stream; + +public class DefaultItemParser extends InputParser { + + public DefaultItemParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + return SuggestionHelper.getNamespacedRegistrySuggestions(ItemType.REGISTRY, input); + } + + @Override + public BaseItem parseFromInput(String input, ParserContext context) throws InputParseException { + BaseItem item = null; + // Legacy matcher + if (context.isTryingLegacy()) { + try { + String[] split = input.split(":"); + ItemType type; + if (split.length == 0) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.invalid-colon")); + } else if (split.length == 1) { + type = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(split[0])); + } else { + type = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(split[0]), Integer.parseInt(split[1])); + } + if (type != null) { + item = new BaseItem(type); + } + } catch (NumberFormatException ignored) { + } + } + + if ("hand".equalsIgnoreCase(input)) { + return getItemInHand(context.requireActor(), HandSide.MAIN_HAND); + } else if ("offhand".equalsIgnoreCase(input)) { + return getItemInHand(context.requireActor(), HandSide.OFF_HAND); + } + + if (item == null) { + ItemType type = ItemTypes.get(input.toLowerCase(Locale.ROOT)); + if (type != null) { + item = new BaseItem(type); + } + } + + if (item == null) { + throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(input))); + } else { + return item; + } + } + + private BaseItemStack getItemInHand(Actor actor, HandSide handSide) throws InputParseException { + if (actor instanceof Player) { + return ((Player) actor).getItemInHand(handSide); + } else { + throw new InputParseException(TranslatableComponent.of( + "worldedit.error.parser.player-only", + TextComponent.of(handSide == HandSide.MAIN_HAND ? "hand" : "offhand") + )); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/AirMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/AirMaskParser.java new file mode 100644 index 0000000..43913f7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/AirMaskParser.java @@ -0,0 +1,50 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.internal.registry.SimpleInputParser; + +import java.util.List; + +public class AirMaskParser extends SimpleInputParser { + + private final List aliases = ImmutableList.of("#air"); + + public AirMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public List getMatchedAliases() { + return aliases; + } + + @Override + public Mask parseFromSimpleInput(String input, ParserContext context) throws InputParseException { + return Masks.negate(new ExistingBlockMask(context.requireExtent())); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java new file mode 100644 index 0000000..e624e2f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java @@ -0,0 +1,84 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.google.common.base.Splitter; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.BiomeMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.registry.InputParser; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.biome.BiomeType; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class BiomeMaskParser extends InputParser { + + public BiomeMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("$"); + } + if (input.charAt(0) == '$') { + input = input.substring(1); + final int lastTermIdx = input.lastIndexOf(','); + if (lastTermIdx <= 0) { + return SuggestionHelper.getNamespacedRegistrySuggestions(BiomeType.REGISTRY, input).map(s -> "$" + s); + } + String prev = input.substring(0, lastTermIdx) + ","; + Set prevBiomes = Arrays.stream(prev.split(",", 0)).collect(Collectors.toSet()); + String search = input.substring(lastTermIdx + 1); + return SuggestionHelper.getNamespacedRegistrySuggestions(BiomeType.REGISTRY, search) + .filter(s -> !prevBiomes.contains(s)).map(s -> "$" + prev + s); + } + return Stream.empty(); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + if (!input.startsWith("$")) { + return null; + } + + Set biomes = new HashSet<>(); + for (String biomeName : Splitter.on(",").split(input.substring(1))) { + BiomeType biome = BiomeType.REGISTRY.get(biomeName); + if (biome == null) { + throw new NoMatchException(TranslatableComponent.of("worldedit.error.unknown-biome", TextComponent.of(biomeName))); + } + biomes.add(biome); + } + + return new BiomeMask(context.requireExtent(), biomes); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java new file mode 100644 index 0000000..05bc406 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.BlockCategoryMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.registry.InputParser; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.block.BlockCategory; + +import java.util.Locale; +import java.util.stream.Stream; + +public class BlockCategoryMaskParser extends InputParser { + + public BlockCategoryMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + return SuggestionHelper.getBlockCategorySuggestions(input, false); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + if (!input.startsWith("##")) { + return null; + } + + // This means it's a tag mask. + BlockCategory category = BlockCategory.REGISTRY.get(input.substring(2).toLowerCase(Locale.ROOT)); + if (category == null) { + throw new NoMatchException(TranslatableComponent.of("worldedit.error.unknown-tag", TextComponent.of(input.substring(2)))); + } else { + return new BlockCategoryMask(context.requireExtent(), category); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java new file mode 100644 index 0000000..1504f42 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java @@ -0,0 +1,64 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.google.common.base.Splitter; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.BlockStateMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.registry.InputParser; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; + +import java.util.stream.Stream; + +public class BlockStateMaskParser extends InputParser { + + public BlockStateMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("^[", "^=["); + } + return Stream.of("^[", "^=[").filter(s -> s.startsWith(input)); // no block type, can't suggest states + } + + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + if (!(input.startsWith("^[") || input.startsWith("^=[")) || !input.endsWith("]")) { + return null; + } + + boolean strict = input.charAt(1) == '='; + String states = input.substring(2 + (strict ? 1 : 0), input.length() - 1); + try { + return new BlockStateMask(context.requireExtent(), + Splitter.on(',').omitEmptyStrings().trimResults().withKeyValueSeparator('=').split(states), + strict); + } catch (Exception e) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.bad-state-format", TextComponent.of(states)), e); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java new file mode 100644 index 0000000..88d64b0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java @@ -0,0 +1,64 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.BlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.world.block.BaseBlock; + +import java.util.Set; +import java.util.stream.Stream; + +/** + * Parses mask input strings. + */ +public class BlocksMaskParser extends InputParser { + + public BlocksMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + return worldEdit.getBlockFactory().getSuggestions(input).stream(); + } + + @Override + public Mask parseFromInput(String component, ParserContext context) throws InputParseException { + ParserContext tempContext = new ParserContext(context); + tempContext.setRestricted(false); + tempContext.setPreferringWildcard(true); + try { + Set holders = worldEdit.getBlockFactory().parseFromListInput(component, tempContext); + if (holders.isEmpty()) { + return null; + } + return new BlockMask(context.requireExtent(), holders); + } catch (NoMatchException e) { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java new file mode 100644 index 0000000..4ec76a2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.registry.SimpleInputParser; + +import java.util.List; + +public class ExistingMaskParser extends SimpleInputParser { + + private final List aliases = ImmutableList.of("#existing"); + + public ExistingMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public List getMatchedAliases() { + return aliases; + } + + @Override + public Mask parseFromSimpleInput(String input, ParserContext context) throws InputParseException { + return new ExistingBlockMask(context.requireExtent()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExposedMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExposedMaskParser.java new file mode 100644 index 0000000..34ea940 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExposedMaskParser.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.mask.OffsetsMask; +import com.sk89q.worldedit.internal.registry.SimpleInputParser; + +import java.util.List; + +public class ExposedMaskParser extends SimpleInputParser { + + private final List aliases = ImmutableList.of("#exposed", "#surface"); + + public ExposedMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public List getMatchedAliases() { + return this.aliases; + } + + @Override + public Mask parseFromSimpleInput(String input, ParserContext context) throws InputParseException { + return OffsetsMask.builder(Masks.negate(new ExistingBlockMask(context.requireExtent()))) + .excludeSelf(true) + .build(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java new file mode 100644 index 0000000..a362840 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java @@ -0,0 +1,73 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.ExpressionMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; +import com.sk89q.worldedit.session.SessionOwner; +import net.kyori.text.TranslatableComponent; + +import java.util.function.IntSupplier; +import java.util.stream.Stream; + +public class ExpressionMaskParser extends InputParser { + + public ExpressionMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("="); + } + return Stream.empty(); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + if (!input.startsWith("=")) { + return null; + } + + try { + Expression exp = Expression.compile(input.substring(1), "x", "y", "z"); + WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment( + context.requireExtent(), Vector3.ONE, Vector3.ZERO); + exp.setEnvironment(env); + if (context.getActor() != null) { + SessionOwner owner = context.getActor(); + IntSupplier timeout = () -> WorldEdit.getInstance().getSessionManager().get(owner).getTimeout(); + return new ExpressionMask(exp, timeout); + } + return new ExpressionMask(exp); + } catch (ExpressionException e) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.invalid-expression")); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/LazyRegionMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/LazyRegionMaskParser.java new file mode 100644 index 0000000..50ac0e1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/LazyRegionMaskParser.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.RegionMask; +import com.sk89q.worldedit.internal.registry.SimpleInputParser; +import com.sk89q.worldedit.session.request.RequestSelection; + +import java.util.List; + +public class LazyRegionMaskParser extends SimpleInputParser { + + private final List aliases = ImmutableList.of("#dregion", "#dselection", "#dsel"); + + public LazyRegionMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public List getMatchedAliases() { + return aliases; + } + + @Override + public Mask parseFromSimpleInput(String input, ParserContext context) { + return new RegionMask(new RequestSelection()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NegateMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NegateMaskParser.java new file mode 100644 index 0000000..1c1f781 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NegateMaskParser.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.internal.registry.InputParser; +import net.kyori.text.TranslatableComponent; + +import java.util.stream.Stream; + +public class NegateMaskParser extends InputParser { + + public NegateMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("!"); + } + if (input.charAt(0) != '!') { + return Stream.empty(); + } + return worldEdit.getMaskFactory().getSuggestions(input.substring(1)).stream().map(s -> "!" + s); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + if (!input.startsWith("!")) { + return null; + } + + if (input.length() > 1) { + return Masks.negate(worldEdit.getMaskFactory().parseFromInput(input.substring(1), context)); + } else { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.negate-nothing")); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NoiseMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NoiseMaskParser.java new file mode 100644 index 0000000..6466aeb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NoiseMaskParser.java @@ -0,0 +1,57 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.NoiseFilter; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.math.noise.RandomNoise; + +import java.util.stream.Stream; + +public class NoiseMaskParser extends InputParser { + + public NoiseMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("%"); + } + if (input.charAt(0) != '%') { + return Stream.empty(); + } + return Stream.of("%10", "%25", "%50", "%75").filter(s -> s.startsWith(input)); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) { + if (!input.startsWith("%")) { + return null; + } + + int i = Integer.parseInt(input.substring(1)); + return new NoiseFilter(new RandomNoise(), ((double) i) / 100); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java new file mode 100644 index 0000000..0ff12b0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java @@ -0,0 +1,66 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.OffsetsMask; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.math.BlockVector3; + +import java.util.stream.Stream; + +public class OffsetMaskParser extends InputParser { + + public OffsetMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of(">", "<"); + } + final char firstChar = input.charAt(0); + if (firstChar != '>' && firstChar != '<') { + return Stream.empty(); + } + return worldEdit.getMaskFactory().getSuggestions(input.substring(1)).stream().map(s -> firstChar + s); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + final char firstChar = input.charAt(0); + if (firstChar != '>' && firstChar != '<') { + return null; + } + + Mask submask; + if (input.length() > 1) { + submask = worldEdit.getMaskFactory().parseFromInput(input.substring(1), context); + } else { + submask = new ExistingBlockMask(context.requireExtent()); + } + return OffsetsMask.single(submask, BlockVector3.at(0, firstChar == '>' ? -1 : 1, 0)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/RegionMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/RegionMaskParser.java new file mode 100644 index 0000000..08c2546 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/RegionMaskParser.java @@ -0,0 +1,55 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.RegionMask; +import com.sk89q.worldedit.internal.registry.SimpleInputParser; +import net.kyori.text.TranslatableComponent; + +import java.util.List; + +public class RegionMaskParser extends SimpleInputParser { + + private final List aliases = ImmutableList.of("#region", "#selection", "#sel"); + + public RegionMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public List getMatchedAliases() { + return aliases; + } + + @Override + public Mask parseFromSimpleInput(String input, ParserContext context) throws InputParseException { + try { + return new RegionMask(context.requireSession().getSelection(context.requireWorld()).clone()); + } catch (IncompleteRegionException e) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.incomplete-region")); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java new file mode 100644 index 0000000..5abaa33 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.mask; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.SolidBlockMask; +import com.sk89q.worldedit.internal.registry.SimpleInputParser; + +import java.util.List; + +public class SolidMaskParser extends SimpleInputParser { + + private final List aliases = ImmutableList.of("#solid"); + + public SolidMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public List getMatchedAliases() { + return aliases; + } + + @Override + public Mask parseFromSimpleInput(String input, ParserContext context) throws InputParseException { + return new SolidBlockMask(context.requireExtent()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java new file mode 100644 index 0000000..e27a230 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java @@ -0,0 +1,84 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.pattern; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomPattern; +import com.sk89q.worldedit.internal.registry.InputParser; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.Locale; +import java.util.Set; +import java.util.stream.Stream; + +public class BlockCategoryPatternParser extends InputParser { + + public BlockCategoryPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + return SuggestionHelper.getBlockCategorySuggestions(input, true); + } + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + if (!input.startsWith("##")) { + return null; + } + String tag = input.substring(2).toLowerCase(Locale.ROOT); + boolean anyState = false; + if (tag.startsWith("*")) { + tag = tag.substring(1); + anyState = true; + } + + BlockCategory category = BlockCategory.REGISTRY.get(tag); + if (category == null) { + throw new NoMatchException(TranslatableComponent.of("worldedit.error.unknown-tag", TextComponent.of(tag))); + } + RandomPattern randomPattern = new RandomPattern(); + + Set blocks = category.getAll(); + if (blocks.isEmpty()) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.empty-tag", TextComponent.of(category.getId()))); + } + + if (anyState) { + blocks.stream().flatMap(blockType -> blockType.getAllStates().stream()).forEach(state -> + randomPattern.add(state, 1.0)); + } else { + for (BlockType blockType : blocks) { + randomPattern.add(blockType.getDefaultState(), 1.0); + } + } + + return randomPattern; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java new file mode 100644 index 0000000..4277b6f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java @@ -0,0 +1,108 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.pattern; + +import com.sk89q.worldedit.EmptyClipboardException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.pattern.ClipboardPattern; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.session.ClipboardHolder; +import net.kyori.text.TranslatableComponent; + +import java.util.Locale; +import java.util.stream.Stream; + +public class ClipboardPatternParser extends InputParser { + + public ClipboardPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("#clipboard"); + } + String[] offsetParts = input.split("@", 2); + String firstLower = offsetParts[0].toLowerCase(Locale.ROOT); + final boolean isClip = "#clipboard".startsWith(firstLower); + final boolean isCopy = "#copy".startsWith(firstLower); + if (isClip || isCopy) { + if (offsetParts.length == 2) { + String coords = offsetParts[1]; + if (coords.isEmpty()) { + return Stream.of(input + "[x,y,z]"); + } + } else { + if (isClip) { + return Stream.of("#clipboard", "#clipboard@[x,y,z]"); + } + return Stream.of("#copy", "#copy@[x,y,z]"); + } + } + return Stream.empty(); + } + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + String[] offsetParts = input.split("@", 2); + if (!offsetParts[0].equalsIgnoreCase("#clipboard") && !offsetParts[0].equalsIgnoreCase("#copy")) { + return null; + } + LocalSession session = context.requireSession(); + + BlockVector3 offset = BlockVector3.ZERO; + if (offsetParts.length == 2) { + String coords = offsetParts[1]; + if (coords.length() < 7 // min length of `[x,y,z]` + || coords.charAt(0) != '[' || coords.charAt(coords.length() - 1) != ']') { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.clipboard.missing-offset")); + } + String[] offsetSplit = coords.substring(1, coords.length() - 1).split(","); + if (offsetSplit.length != 3) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.clipboard.missing-coordinates")); + } + offset = BlockVector3.at( + Integer.parseInt(offsetSplit[0]), + Integer.parseInt(offsetSplit[1]), + Integer.parseInt(offsetSplit[2]) + ); + } + + if (session != null) { + try { + ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); + return new ClipboardPattern(clipboard, offset); + } catch (EmptyClipboardException e) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.empty-clipboard")); + } + } else { + throw new InputParseException(TranslatableComponent.of("worldedit.error.missing-session")); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomPatternParser.java new file mode 100644 index 0000000..c11ebed --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomPatternParser.java @@ -0,0 +1,96 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.pattern; + +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomPattern; +import com.sk89q.worldedit.internal.registry.InputParser; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; + +import java.util.List; +import java.util.stream.Stream; + +public class RandomPatternParser extends InputParser { + + private final java.util.regex.Pattern regex = java.util.regex.Pattern.compile("[0-9]+(\\.[0-9]*)?%.*"); + + public RandomPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + String[] splits = input.split(",", -1); + List patterns = StringUtil.parseListInQuotes(splits, ',', '[', ']', true); + // get suggestions for the last token only + String percent = null; + String token = patterns.get(patterns.size() - 1); + if (regex.matcher(token).matches()) { + String[] p = token.split("%", 2); + percent = p[0]; + token = p[1]; + } else if (patterns.size() == 1) { + return Stream.empty(); // handled by DefaultBlockParser + } + String previous = patterns.size() == 1 ? "" : String.join(",", patterns.subList(0, patterns.size() - 1)) + ","; + String prefix = previous + (percent == null ? "" : percent + "%"); + final List innerSuggestions = worldEdit.getPatternFactory().getSuggestions(token); + return innerSuggestions.stream().map(s -> prefix + s); + } + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + RandomPattern randomPattern = new RandomPattern(); + + String[] splits = input.split(",", -1); + List patterns = StringUtil.parseListInQuotes(splits, ',', '[', ']', true); + if (patterns.size() == 1) { + return null; // let a 'single'-pattern parser handle it + } + for (String token : patterns) { + double chance; + Pattern innerPattern; + + // Parse special percentage syntax + if (token.matches("[0-9]+(\\.[0-9]*)?%.*")) { + String[] p = token.split("%"); + + if (p.length < 2) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.missing-random-type", TextComponent.of(input))); + } else { + chance = Double.parseDouble(p[0]); + innerPattern = worldEdit.getPatternFactory().parseFromInput(p[1], context); + } + } else { + chance = 1; + innerPattern = worldEdit.getPatternFactory().parseFromInput(token, context); + } + + randomPattern.add(innerPattern, chance); + } + + return randomPattern; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java new file mode 100644 index 0000000..b3096f5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.pattern; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomStatePattern; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.FuzzyBlockState; + +import java.util.stream.Stream; + +public class RandomStatePatternParser extends InputParser { + public RandomStatePatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("*"); + } + if (!input.startsWith("*")) { + return Stream.empty(); + } + + return worldEdit.getBlockFactory().getSuggestions(input.substring(1)).stream().map(s -> "*" + s); + } + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + if (!input.startsWith("*")) { + return null; + } + + boolean wasFuzzy = context.isPreferringWildcard(); + context.setPreferringWildcard(true); + BaseBlock block = worldEdit.getBlockFactory().parseFromInput(input.substring(1), context); + context.setPreferringWildcard(wasFuzzy); + if (block.getStates().size() == block.getBlockType().getPropertyMap().size()) { + // they requested random with *, but didn't leave any states empty - simplify + return block; + } else if (block.toImmutableState() instanceof FuzzyBlockState) { + return new RandomStatePattern((FuzzyBlockState) block.toImmutableState()); + } else { + return null; // only should happen if parseLogic changes + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java new file mode 100644 index 0000000..bbc0054 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java @@ -0,0 +1,46 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.pattern; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.registry.InputParser; + +import java.util.stream.Stream; + +public class SingleBlockPatternParser extends InputParser { + + public SingleBlockPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + return worldEdit.getBlockFactory().getSuggestions(input).stream(); + } + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + return worldEdit.getBlockFactory().parseFromInput(input, context); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java new file mode 100644 index 0000000..a1df486 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java @@ -0,0 +1,124 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.factory.parser.pattern; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.buffer.ExtentBuffer; +import com.sk89q.worldedit.function.pattern.ExtentBufferedCompositePattern; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.StateApplyingPattern; +import com.sk89q.worldedit.function.pattern.TypeApplyingPattern; +import com.sk89q.worldedit.internal.registry.InputParser; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + + +public class TypeOrStateApplyingPatternParser extends InputParser { + + public TypeOrStateApplyingPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("^"); + } + if (!input.startsWith("^")) { + return Stream.empty(); + } + input = input.substring(1); + + String[] parts = input.split("\\[", 2); + String type = parts[0]; + + if (parts.length == 1) { + return worldEdit.getBlockFactory().getSuggestions(input).stream().map(s -> "^" + s); + } else { + if (type.isEmpty()) { + return Stream.empty(); // without knowing a type, we can't really suggest states + } else { + return SuggestionHelper.getBlockPropertySuggestions(type, parts[1]).map(s -> "^" + s); + } + } + } + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + if (!input.startsWith("^")) { + return null; + } + Extent extent = context.requireExtent(); + input = input.substring(1); + + String[] parts = input.split("\\[", 2); + String type = parts[0]; + + if (parts.length == 1) { + return new TypeApplyingPattern(extent, + worldEdit.getBlockFactory().parseFromInput(type, context).getBlockType().getDefaultState()); + } else { + // states given + if (!parts[1].endsWith("]")) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.missing-rbracket")); + } + final String[] states = parts[1].substring(0, parts[1].length() - 1).split(","); + Map statesToSet = new HashMap<>(); + for (String state : states) { + if (state.isEmpty()) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.empty-state")); + } + String[] propVal = state.split("=", 2); + if (propVal.length != 2) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.missing-equals-separator")); + } + final String prop = propVal[0]; + if (prop.isEmpty()) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.empty-property")); + } + final String value = propVal[1]; + if (value.isEmpty()) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.empty-value")); + } + if (statesToSet.put(prop, value) != null) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.duplicate-property", TextComponent.of(prop))); + } + } + if (type.isEmpty()) { + return new StateApplyingPattern(extent, statesToSet); + } else { + Extent buffer = new ExtentBuffer(extent); + Pattern typeApplier = new TypeApplyingPattern(buffer, + worldEdit.getBlockFactory().parseFromInput(type, context).getBlockType().getDefaultState()); + Pattern stateApplier = new StateApplyingPattern(buffer, statesToSet); + return new ExtentBufferedCompositePattern(buffer, typeApplier, stateApplier); + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/input/DisallowedUsageException.java b/src/main/java/com/sk89q/worldedit/extension/input/DisallowedUsageException.java new file mode 100644 index 0000000..ba03020 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/input/DisallowedUsageException.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.input; + +import net.kyori.text.Component; + +/** + * Thrown when usage is disallowed. + */ +public class DisallowedUsageException extends InputParseException { + + /** + * Create with a message. + * + * @param message the message + */ + public DisallowedUsageException(Component message) { + super(message); + } + + /** + * Create with a message. + * + * @param message the message + */ + @Deprecated + public DisallowedUsageException(String message) { + super(message); + } + + /** + * Create with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + public DisallowedUsageException(Component message, Throwable cause) { + super(message, cause); + } + + /** + * Create with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + @Deprecated + public DisallowedUsageException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/input/InputParseException.java b/src/main/java/com/sk89q/worldedit/extension/input/InputParseException.java new file mode 100644 index 0000000..f037a94 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/input/InputParseException.java @@ -0,0 +1,70 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.input; + +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.Component; + +/** + * Thrown when parsed input results in an error. + */ +public class InputParseException extends WorldEditException { + + /** + * Throw with a message. + * + * @param message the message + */ + public InputParseException(Component message) { + super(message); + } + + /** + * Throw with a message. + * + * @param message the message + */ + @Deprecated + public InputParseException(String message) { + super(message); + } + + /** + * Throw with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + public InputParseException(Component message, Throwable cause) { + super(message, cause); + } + + /** + * Throw with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + @Deprecated + public InputParseException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/input/NoMatchException.java b/src/main/java/com/sk89q/worldedit/extension/input/NoMatchException.java new file mode 100644 index 0000000..df9248c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/input/NoMatchException.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.input; + +import net.kyori.text.Component; + +/** + * Thrown when a match fails when input is parsed. + */ +public class NoMatchException extends InputParseException { + + /** + * Create with a message. + * + * @param message the message + */ + public NoMatchException(Component message) { + super(message); + } + + /** + * Create with a message. + * + * @param message the message + */ + @Deprecated + public NoMatchException(String message) { + super(message); + } + + /** + * Create with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + public NoMatchException(Component message, Throwable cause) { + super(message, cause); + } + + /** + * Create with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + @Deprecated + public NoMatchException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java b/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java new file mode 100644 index 0000000..503f1b5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java @@ -0,0 +1,252 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.input; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.factory.MaskFactory; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.Extent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; + +/** + * Contains contextual information that may be useful when constructing + * objects from a registry (such as {@link MaskFactory}). + * + *

By default, {@link #isRestricted()} will return true.

+ */ +public class ParserContext { + + private @Nullable Extent extent; + private @Nullable LocalSession session; + private @Nullable World world; + private @Nullable Actor actor; + private boolean restricted = true; + private boolean tryLegacy = true; + private boolean preferringWildcard; + + /** + * Create a new instance. + */ + public ParserContext() { + } + + /** + * Creates a copy of another instance. + * + * @param other the other instance + */ + public ParserContext(ParserContext other) { + setExtent(other.getExtent()); + setSession(other.getSession()); + setWorld(other.getWorld()); + setActor(other.getActor()); + setRestricted(other.isRestricted()); + setPreferringWildcard(other.isPreferringWildcard()); + setTryLegacy(other.isTryingLegacy()); + } + + /** + * Get the {@link Extent} set on this context. + * + * @return an extent + */ + public @Nullable Extent getExtent() { + return extent; + } + + /** + * Set the extent. + * + * @param extent an extent, or null if none is available + */ + public void setExtent(@Nullable Extent extent) { + this.extent = extent; + } + + /** + * Get the {@link LocalSession}. + * + * @return a session + */ + public @Nullable LocalSession getSession() { + return session; + } + + /** + * Set the session. + * + * @param session a session, or null if none is available + */ + public void setSession(@Nullable LocalSession session) { + this.session = session; + } + + /** + * Get the {@link World} set on this context. + * + * @return a world + */ + public @Nullable World getWorld() { + return world; + } + + /** + * Set the world. + * + * @param world a world, or null if none is available + */ + public void setWorld(@Nullable World world) { + this.world = world; + setExtent(world); + } + + /** + * Get the {@link Actor} set on this context. + * + * @return an actor, or null + */ + public @Nullable Actor getActor() { + return actor; + } + + /** + * Set the actor. + * + * @param actor an actor, or null if none is available + */ + public void setActor(@Nullable Actor actor) { + this.actor = actor; + } + + /** + * Get the {@link Extent} set on this context. + * + * @return an extent + * @throws InputParseException thrown if no {@link Extent} is set + */ + public Extent requireExtent() throws InputParseException { + Extent extent = getExtent(); + if (extent == null) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.missing-extent")); + } + return extent; + } + + /** + * Get the {@link LocalSession}. + * + * @return a session + * @throws InputParseException thrown if no {@link LocalSession} is set + */ + public LocalSession requireSession() throws InputParseException { + LocalSession session = getSession(); + if (session == null) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.missing-session")); + } + return session; + } + + /** + * Get the {@link World} set on this context. + * + * @return a world + * @throws InputParseException thrown if no {@link World} is set + */ + public World requireWorld() throws InputParseException { + World world = getWorld(); + if (world == null) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.missing-world")); + } + return world; + } + + /** + * Get the {@link Actor} set on this context. + * + * @return an actor + * @throws InputParseException thrown if no {@link Actor} is set + */ + public Actor requireActor() throws InputParseException { + Actor actor = getActor(); + if (actor == null) { + throw new InputParseException(TranslatableComponent.of("worldedit.error.missing-actor")); + } + return actor; + } + + /** + * Returns whether there should be restrictions (as a result of + * limits or permissions) considered when parsing the input. + * + * @return true if restricted + */ + public boolean isRestricted() { + return restricted; + } + + /** + * Set whether there should be restrictions (as a result of + * limits or permissions) considered when parsing the input. + * + * @param restricted true if restricted + */ + public void setRestricted(boolean restricted) { + this.restricted = restricted; + } + + /** + * Get whether wildcards are preferred. + * + * @return true if wildcards are preferred + */ + public boolean isPreferringWildcard() { + return preferringWildcard; + } + + /** + * Set whether wildcards are preferred. + * + * @param preferringWildcard true if wildcards are preferred + */ + public void setPreferringWildcard(boolean preferringWildcard) { + this.preferringWildcard = preferringWildcard; + } + + /** + * Set whether legacy IDs should be attempted. + * + * @param tryLegacy true if legacy IDs should be attempted + */ + public void setTryLegacy(boolean tryLegacy) { + this.tryLegacy = tryLegacy; + } + + /** + * Get whether legacy IDs should be tried. + * + * @return true if legacy should be tried + */ + public boolean isTryingLegacy() { + return tryLegacy; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/AbstractCommandBlockActor.java b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractCommandBlockActor.java new file mode 100644 index 0000000..d18c702 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractCommandBlockActor.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Location; + +public abstract class AbstractCommandBlockActor extends AbstractNonPlayerActor implements Locatable { + protected static final String UUID_PREFIX = "CMD"; + + private final Location location; + + public AbstractCommandBlockActor(Location location) { + this.location = location; + } + + @Override + public Location getLocation() { + return this.location; + } + + @Override + public boolean setLocation(Location location) { + // Can't move a CommandBlock + return false; + } + + @Override + public Extent getExtent() { + return this.location.getExtent(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java new file mode 100644 index 0000000..de51c65 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java @@ -0,0 +1,51 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.internal.cui.CUIEvent; + +import java.io.File; + +public abstract class AbstractNonPlayerActor implements Actor { + + @Override + public boolean canDestroyBedrock() { + return true; + } + + @Override + public boolean isPlayer() { + return false; + } + + @Override + public File openFileOpenDialog(String[] extensions) { + return null; + } + + @Override + public File openFileSaveDialog(String[] extensions) { + return null; + } + + @Override + public void dispatchCUIEvent(CUIEvent event) { + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java new file mode 100644 index 0000000..3bf41a1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java @@ -0,0 +1,91 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.io.ResourceLoader; +import com.sk89q.worldedit.util.io.WorldEditResourceLoader; +import com.sk89q.worldedit.util.io.file.ArchiveUnpacker; +import com.sk89q.worldedit.util.translation.TranslationManager; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.World; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Collections; +import java.util.List; + +/** + * An abstract implementation of {@link Platform}. + */ +public abstract class AbstractPlatform implements Platform { + + private final ResourceLoader resourceLoader = new WorldEditResourceLoader(WorldEdit.getInstance()); + private final LazyReference archiveUnpacker = LazyReference.from(() -> { + try { + return new ArchiveUnpacker(getConfiguration().getWorkingDirectoryPath().resolve(".archive-unpack")); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + private final LazyReference translationManager = LazyReference.from(() -> { + try { + return new TranslationManager(archiveUnpacker.getValue(), getResourceLoader()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + + @Override + public ResourceLoader getResourceLoader() { + return resourceLoader; + } + + @Override + public TranslationManager getTranslationManager() { + return translationManager.getValue(); + } + + @Override + public int schedule(long delay, long period, Runnable task) { + return -1; + } + + @Override + public List getWorlds() { + return Collections.emptyList(); + } + + @Override + public DataFixer getDataFixer() { + return null; + } + + @Override + public void reload() { + getTranslationManager().reload(); + } + + @Override + public long getTickCount() { + return System.nanoTime() / 50_000_000; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java new file mode 100644 index 0000000..cc1e8f0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -0,0 +1,570 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.NotABlockException; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.TargetBlock; +import com.sk89q.worldedit.util.auth.AuthorizationException; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockCategories; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.gamemode.GameMode; +import com.sk89q.worldedit.world.gamemode.GameModes; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; + +import java.io.File; +import javax.annotation.Nullable; + +/** + * An abstract implementation of both a {@link Actor} and a {@link Player} + * that is intended for implementations of WorldEdit to use to wrap + * players that make use of WorldEdit. + */ +public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { + + @Override + public final Extent getExtent() { + return getWorld(); + } + + /** + * Returns direction according to rotation. May return null. + * + * @param rot yaw + * @return the direction + */ + private static Direction getDirection(double rot) { + if (0 <= rot && rot < 22.5) { + return Direction.SOUTH; + } else if (22.5 <= rot && rot < 67.5) { + return Direction.SOUTHWEST; + } else if (67.5 <= rot && rot < 112.5) { + return Direction.WEST; + } else if (112.5 <= rot && rot < 157.5) { + return Direction.NORTHWEST; + } else if (157.5 <= rot && rot < 202.5) { + return Direction.NORTH; + } else if (202.5 <= rot && rot < 247.5) { + return Direction.NORTHEAST; + } else if (247.5 <= rot && rot < 292.5) { + return Direction.EAST; + } else if (292.5 <= rot && rot < 337.5) { + return Direction.SOUTHEAST; + } else if (337.5 <= rot && rot < 360.0) { + return Direction.SOUTH; + } else { + return null; + } + } + + @Override + public boolean isHoldingPickAxe() { + ItemType item = getItemInHand(HandSide.MAIN_HAND).getType(); + return item == ItemTypes.IRON_PICKAXE + || item == ItemTypes.WOODEN_PICKAXE + || item == ItemTypes.STONE_PICKAXE + || item == ItemTypes.DIAMOND_PICKAXE + || item == ItemTypes.GOLDEN_PICKAXE + || item == ItemTypes.NETHERITE_PICKAXE; + } + + @Override + public void findFreePosition(Location searchPos) { + Extent world = searchPos.getExtent(); + + int worldMinY = world.getMinimumPoint().getY(); + int worldMaxY = world.getMaximumPoint().getY(); + + int x = searchPos.getBlockX(); + int y = Math.max(worldMinY, searchPos.getBlockY()); + int origY = y; + int z = searchPos.getBlockZ(); + int yPlusSearchHeight = y + WorldEdit.getInstance().getConfiguration().defaultVerticalHeight; + int maxY = Math.min(worldMaxY, yPlusSearchHeight) + 2; + + byte free = 0; + + while (y <= maxY) { + if (!world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) { + ++free; + } else { + free = 0; + } + + if (free == 2) { + boolean worked = true; + + if (y - 1 != origY) { + worked = trySetPosition(Vector3.at(x + 0.5, y - 2 + 1, z + 0.5)); + } + + if (worked) { + return; + } + } + + ++y; + } + } + + @Override + public void setOnGround(Location searchPos) { + Extent world = searchPos.getExtent(); + + int worldMinY = world.getMinimumPoint().getY(); + + int x = searchPos.getBlockX(); + int y = Math.max(worldMinY, searchPos.getBlockY()); + int z = searchPos.getBlockZ(); + int yLessSearchHeight = y - WorldEdit.getInstance().getConfiguration().defaultVerticalHeight; + int minY = Math.min(worldMinY, yLessSearchHeight) + 2; + + while (y >= minY) { + final BlockVector3 pos = BlockVector3.at(x, y, z); + final BlockState id = world.getBlock(pos); + if (id.getBlockType().getMaterial().isMovementBlocker() + && trySetPosition(Vector3.at(x + 0.5, y + 1, z + 0.5))) { + return; + } + + --y; + } + } + + @Override + public void findFreePosition() { + findFreePosition(getBlockLocation()); + } + + /** + * Determines if the block at the given location "harms" the player, either by suffocation + * or other means. + */ + private boolean isPlayerHarmingBlock(BlockVector3 location) { + BlockType type = getWorld().getBlock(location).getBlockType(); + return type.getMaterial().isMovementBlocker() || type == BlockTypes.LAVA + || BlockCategories.FIRE.contains(type); + } + + /** + * Check if the location is a good place to leave a standing player. + * + * @param location where the player would be placed (not Y offset) + * @return if the player can stand at the location + */ + private boolean isLocationGoodForStanding(BlockVector3 location) { + if (isPlayerHarmingBlock(location.add(0, 1, 0))) { + return false; + } + if (isPlayerHarmingBlock(location)) { + return false; + } + return getWorld().getBlock(location.add(0, -1, 0)).getBlockType().getMaterial() + .isMovementBlocker(); + } + + @Override + public boolean ascendLevel() { + final World world = getWorld(); + final Location pos = getBlockLocation(); + final int x = pos.getBlockX(); + int y = Math.max(world.getMinY(), pos.getBlockY() + 1); + final int z = pos.getBlockZ(); + int yPlusSearchHeight = y + WorldEdit.getInstance().getConfiguration().defaultVerticalHeight; + int maxY = Math.min(world.getMaxY(), yPlusSearchHeight) + 2; + + while (y <= maxY) { + if (isLocationGoodForStanding(BlockVector3.at(x, y, z)) + && trySetPosition(Vector3.at(x + 0.5, y, z + 0.5))) { + return true; + } + + ++y; + } + + return false; + } + + @Override + public boolean descendLevel() { + final World world = getWorld(); + final Location pos = getBlockLocation(); + final int x = pos.getBlockX(); + int y = Math.max(world.getMinY(), pos.getBlockY() - 1); + final int z = pos.getBlockZ(); + int yLessSearchHeight = y - WorldEdit.getInstance().getConfiguration().defaultVerticalHeight; + int minY = Math.min(world.getMinY() + 1, yLessSearchHeight); + + while (y >= minY) { + if (isLocationGoodForStanding(BlockVector3.at(x, y, z)) + && trySetPosition(Vector3.at(x + 0.5, y, z + 0.5))) { + return true; + } + + --y; + } + + return false; + } + + @Override + public boolean ascendToCeiling(int clearance) { + return ascendToCeiling(clearance, true); + } + + @Override + public boolean ascendToCeiling(int clearance, boolean alwaysGlass) { + World world = getWorld(); + Location pos = getBlockLocation(); + int x = pos.getBlockX(); + int initialY = Math.max(world.getMinY(), pos.getBlockY()); + int y = Math.max(world.getMinY(), pos.getBlockY() + 2); + int z = pos.getBlockZ(); + + // No free space above + if (!world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isAir()) { + return false; + } + + int yPlusSearchHeight = y + WorldEdit.getInstance().getConfiguration().defaultVerticalHeight; + int maxY = Math.min(world.getMaxY(), yPlusSearchHeight); + + while (y <= maxY) { + // Found a ceiling! + if (world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) { + int platformY = Math.max(initialY, y - 3 - clearance); + if (platformY < initialY) { // if ==, they already have the given clearance, if <, clearance is too large + return false; + } else if (platformY == initialY) { + return false; + } + floatAt(x, platformY + 1, z, alwaysGlass); + return true; + } + + ++y; + } + + return false; + } + + @Override + public boolean ascendUpwards(int distance) { + return ascendUpwards(distance, true); + } + + @Override + public boolean ascendUpwards(int distance, boolean alwaysGlass) { + final World world = getWorld(); + final Location pos = getBlockLocation(); + final int x = pos.getBlockX(); + final int initialY = Math.max(world.getMinY(), pos.getBlockY()); + int y = Math.max(world.getMinY(), pos.getBlockY() + 1); + final int z = pos.getBlockZ(); + final int maxY = Math.min(world.getMaxY() + 1, initialY + distance); + + while (y <= world.getMaxY() + 2) { + if (world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) { + break; // Hit something + } else if (y > maxY + 1) { + break; + } else if (y == maxY + 1) { + floatAt(x, y - 1, z, alwaysGlass); + return true; + } + + ++y; + } + + return false; + } + + @Override + public void floatAt(int x, int y, int z, boolean alwaysGlass) { + if (alwaysGlass || !isAllowedToFly()) { + BlockVector3 spot = BlockVector3.at(x, y - 1, z); + final World world = getWorld(); + if (!world.getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) { + try (EditSession session = WorldEdit.getInstance().newEditSession(this)) { + session.setBlock(spot, BlockTypes.GLASS.getDefaultState()); + } catch (MaxChangedBlocksException ignored) { + } + } + } else { + setFlying(true); + } + trySetPosition(Vector3.at(x + 0.5, y, z + 0.5)); + } + + /** + * Check whether the player is allowed to fly. + * + * @return true if allowed flight + */ + protected boolean isAllowedToFly() { + return false; + } + + /** + * Set whether the player is currently flying. + * + * @param flying true to fly + */ + protected void setFlying(boolean flying) { + } + + @Override + public Location getBlockOn() { + final Location location = getLocation(); + return location.setPosition(location.setY(location.getY() - 1).toVector().floor()); + } + + @Override + public Location getBlockTrace(int range, boolean useLastBlock) { + return getBlockTrace(range, useLastBlock, null); + } + + @Override + public Location getBlockTraceFace(int range, boolean useLastBlock) { + return getBlockTraceFace(range, useLastBlock, null); + } + + @Override + public Location getBlockTrace(int range, boolean useLastBlock, @Nullable Mask stopMask) { + TargetBlock tb = new TargetBlock(this, range, 0.2); + if (stopMask != null) { + tb.setStopMask(stopMask); + } + return (useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock()); + } + + @Override + public Location getBlockTraceFace(int range, boolean useLastBlock, @Nullable Mask stopMask) { + TargetBlock tb = new TargetBlock(this, range, 0.2); + if (stopMask != null) { + tb.setStopMask(stopMask); + } + return (useLastBlock ? tb.getAnyTargetBlockFace() : tb.getTargetBlockFace()); + } + + @Override + public Location getBlockTrace(int range) { + return getBlockTrace(range, false); + } + + @Override + public Location getSolidBlockTrace(int range) { + TargetBlock tb = new TargetBlock(this, range, 0.2); + return tb.getSolidTargetBlock(); + } + + @Override + public Direction getCardinalDirection() { + return getCardinalDirection(0); + } + + @Override + public Direction getCardinalDirection(int yawOffset) { + final Location location = getLocation(); + if (location.getPitch() > 67.5) { + return Direction.DOWN; + } + if (location.getPitch() < -67.5) { + return Direction.UP; + } + + // From hey0's code + double rot = (location.getYaw() + yawOffset) % 360; //let's use real yaw now + if (rot < 0) { + rot += 360.0; + } + return getDirection(rot); + } + + @Override + public BaseBlock getBlockInHand(HandSide handSide) throws WorldEditException { + final ItemType typeId = getItemInHand(handSide).getType(); + if (typeId.hasBlockType()) { + return typeId.getBlockType().getDefaultState().toBaseBlock(); + } else { + throw new NotABlockException(typeId); + } + } + + private boolean canPassThroughBlock(Location curBlock) { + BlockVector3 blockPos = curBlock.toVector().toBlockPoint(); + BlockState block = curBlock.getExtent().getBlock(blockPos); + return !block.getBlockType().getMaterial().isMovementBlocker(); + } + + /** + * Advances the block target block until the current block is a wall. + * + * @return true if a wall is found + */ + private boolean advanceToWall(TargetBlock hitBlox) { + Location curBlock; + while ((curBlock = hitBlox.getCurrentBlock()) != null) { + if (!canPassThroughBlock(curBlock)) { + return true; + } + + hitBlox.getNextBlock(); + } + + return false; + } + + /** + * Advances the block target block until the current block is a free spot. + * + * @return true if a free spot is found + */ + private boolean advanceToFree(TargetBlock hitBlox) { + Location curBlock; + while ((curBlock = hitBlox.getCurrentBlock()) != null) { + if (canPassThroughBlock(curBlock)) { + return true; + } + + hitBlox.getNextBlock(); + } + + return false; + } + + @Override + public boolean passThroughForwardWall(int range) { + TargetBlock hitBlox = new TargetBlock(this, range, 0.2); + + if (!advanceToWall(hitBlox)) { + return false; + } + + if (!advanceToFree(hitBlox)) { + return false; + } + + Location foundBlock = hitBlox.getCurrentBlock(); + if (foundBlock != null) { + setOnGround(foundBlock); + return true; + } + + return false; + } + + @Override + public boolean trySetPosition(Vector3 pos) { + final Location location = getLocation(); + return trySetPosition(pos, location.getPitch(), location.getYaw()); + } + + @Override + public File openFileOpenDialog(String[] extensions) { + printError(TranslatableComponent.of("worldedit.platform.no-file-dialog")); + return null; + } + + @Override + public File openFileSaveDialog(String[] extensions) { + printError(TranslatableComponent.of("worldedit.platform.no-file-dialog")); + return null; + } + + @Override + public boolean canDestroyBedrock() { + return hasPermission("worldedit.override.bedrock"); + } + + @Override + public void dispatchCUIEvent(CUIEvent event) { + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Player)) { + return false; + } + Player other2 = (Player) other; + return other2.getName().equals(getName()); + } + + @Override + public int hashCode() { + return getName().hashCode(); + } + + @Override + public void checkPermission(String permission) throws AuthorizationException { + if (!hasPermission(permission)) { + throw new AuthorizationException(); + } + } + + @Override + public boolean isPlayer() { + return true; + } + + @Override + public GameMode getGameMode() { + return GameModes.SURVIVAL; + } + + @Override + public void setGameMode(GameMode gameMode) { + + } + + @Override + public Object clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException("Not supported"); + } + + @Override + public boolean remove() { + return false; + } + + @Override + public > void sendFakeBlock(BlockVector3 pos, B block) { + + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java b/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java new file mode 100644 index 0000000..8aef289 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java @@ -0,0 +1,172 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.session.SessionOwner; +import com.sk89q.worldedit.util.Identifiable; +import com.sk89q.worldedit.util.auth.Subject; +import net.kyori.text.Component; +import net.kyori.text.format.TextColor; + +import java.io.File; +import java.util.Locale; + +/** + * An object that can perform actions in WorldEdit. + */ +public interface Actor extends Identifiable, SessionOwner, Subject { + + /** + * Get the name of the actor. + * + * @return String + */ + String getName(); + + /** + * Gets the display name of the actor. This can be a nickname, and is not guaranteed to be unique. + * + * @return The display name + */ + default String getDisplayName() { + return getName(); + } + + /** + * Print a message. + * + * @param msg The message text + * @deprecated Use component-based functions (print) + */ + @Deprecated + void printRaw(String msg); + + /** + * Print a WorldEdit message. + * + * @param msg The message text + * @deprecated Use component-based functions (printDebug) + */ + @Deprecated + void printDebug(String msg); + + /** + * Print a WorldEdit message. + * + * @param msg The message text + * @deprecated Use component-based functions (printInfo) + */ + @Deprecated + void print(String msg); + + /** + * Print a WorldEdit error. + * + * @param msg The error message text + * @deprecated Use component-based functions (printError) + */ + @Deprecated + void printError(String msg); + + /** + * Print a WorldEdit error. + * + * @param component The component to print + */ + default void printError(Component component) { + print(component.color(TextColor.RED)); + } + + /** + * Print a WorldEdit message. + * + * @param component The component to print + */ + default void printInfo(Component component) { + print(component.color(TextColor.LIGHT_PURPLE)); + } + + /** + * Print a WorldEdit message. + * + * @param component The component to print + */ + default void printDebug(Component component) { + print(component.color(TextColor.GRAY)); + } + + /** + * Print a {@link Component}. + * + * @param component The component to print + */ + void print(Component component); + + /** + * Returns true if the actor can destroy bedrock. + * + * @return true if bedrock can be broken by the actor + */ + boolean canDestroyBedrock(); + + /** + * Return whether this actor is a player. + * + * @return true if a player + */ + boolean isPlayer(); + + /** + * Open a file open dialog. + * + * @param extensions null to allow all + * @return the selected file or null if something went wrong + */ + File openFileOpenDialog(String[] extensions); + + /** + * Open a file save dialog. + * + * @param extensions null to allow all + * @return the selected file or null if something went wrong + */ + File openFileSaveDialog(String[] extensions); + + /** + * Send a CUI event. + * + * @param event the event + */ + void dispatchCUIEvent(CUIEvent event); + + /** + * Get the locale of this actor. + * + * @return The locale + */ + Locale getLocale(); + + /** + * Sends any relevant notices to the user when they first use WorldEdit in a session. + */ + default void sendAnnouncements() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java b/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java new file mode 100644 index 0000000..be34b5e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java @@ -0,0 +1,136 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BlockRegistry; + +/** + * A collection of capabilities that a {@link Platform} may support. + */ +public enum Capability { + + /** + * The capability of registering game hooks to catch events such as + * a player clicking a block. + */ + GAME_HOOKS { + @Override + void initialize(PlatformManager platformManager, Platform platform) { + platform.setGameHooksEnabled(true); + } + + @Override + void uninitialize(PlatformManager platformManager, Platform platform) { + platform.setGameHooksEnabled(false); + } + }, + + /** + * The capability of providing configuration. + */ + CONFIGURATION { + @Override + void initialize(PlatformManager platformManager, Platform platform) { + WorldEdit.getInstance().getAssetLoaders().init(); + } + + @Override + void uninitialize(PlatformManager platformManager, Platform platform) { + WorldEdit.getInstance().getAssetLoaders().uninit(); + } + }, + + /** + * The capability of handling user commands entered in chat or console. + */ + USER_COMMANDS { + @Override + void initialize(PlatformManager platformManager, Platform platform) { + platformManager.getPlatformCommandManager().registerCommandsWith(platform); + } + + @Override + void uninitialize(PlatformManager platformManager, Platform platform) { + platformManager.getPlatformCommandManager().removeCommands(); + } + }, + + /** + * The capability of a platform to assess whether a given + * {@link Actor} has sufficient authorization to perform a task. + */ + PERMISSIONS, + + /** + * The capability of a platform to dispatch WorldEditCUI events. + */ + WORLDEDIT_CUI, + + /** + * The capability of a platform to perform modifications to a world. + */ + WORLD_EDITING { + @Override + void ready(PlatformManager platformManager, Platform platform) { + BlockRegistry blockRegistry = platform.getRegistries().getBlockRegistry(); + for (BlockType type : BlockType.REGISTRY) { + for (BlockState state : type.getAllStates()) { + BlockStateIdAccess.register(state, + blockRegistry.getInternalBlockStateId(state) + .orElse(BlockStateIdAccess.invalidId())); + } + } + } + + @Override + void unready(PlatformManager platformManager, Platform platform) { + BlockStateIdAccess.clear(); + } + }; + + /** + * Initialize platform-wide state. + */ + void initialize(PlatformManager platformManager, Platform platform) { + } + + /** + * Un-initialize platform-wide state. + */ + void uninitialize(PlatformManager platformManager, Platform platform) { + } + + /** + * Initialize per-level state. + */ + void ready(PlatformManager platformManager, Platform platform) { + } + + /** + * Un-initialize per-level state. + */ + void unready(PlatformManager platformManager, Platform platform) { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/Locatable.java b/src/main/java/com/sk89q/worldedit/extension/platform/Locatable.java new file mode 100644 index 0000000..2acb333 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/Locatable.java @@ -0,0 +1,87 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.Location; + +public interface Locatable { + + /** + * Get the location of this actor. + * + * @return the location of the actor + */ + Location getLocation(); + + /** + * Get the location of this actor in block coordinates. + * + * @return the block location of the actor + */ + default Location getBlockLocation() { + Location location = getLocation(); + return location.setPosition(location.toVector().floor()); + } + + /** + * Sets the location of this actor. + * + * @param location the new location of the actor + * @return if the teleport succeeded + */ + boolean setLocation(Location location); + + /** + * Sets the position of this actor. + * + * @param pos where to move them + * @deprecated This method may fail without indication. Use {@link #trySetPosition(Vector3)} + * instead + */ + @Deprecated + default void setPosition(Vector3 pos) { + trySetPosition(pos); + } + + /** + * Attempts to set the position of this actor. + * + *

+ * This action may fail, due to other mods cancelling the move. + * If so, this method will return {@code false}. + *

+ * + * @param pos the position to set + * @return if the position was able to be set + */ + default boolean trySetPosition(Vector3 pos) { + return setLocation(new Location(getExtent(), pos)); + } + + /** + * Get the extent that this actor is in. + * + * @return the extent + */ + Extent getExtent(); + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/MultiUserPlatform.java b/src/main/java/com/sk89q/worldedit/extension/platform/MultiUserPlatform.java new file mode 100644 index 0000000..c690024 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/MultiUserPlatform.java @@ -0,0 +1,36 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import java.util.Collection; + +/** + * Implements a platform with multiple connected users. + */ +public interface MultiUserPlatform extends Platform { + + /** + * Get a list of connected users. + * + * @return a list of connected users + */ + Collection getConnectedUsers(); + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/NoCapablePlatformException.java b/src/main/java/com/sk89q/worldedit/extension/platform/NoCapablePlatformException.java new file mode 100644 index 0000000..d456206 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/NoCapablePlatformException.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +/** + * Thrown when no capable platform is found. + */ +public class NoCapablePlatformException extends RuntimeException { + + public NoCapablePlatformException() { + } + + public NoCapablePlatformException(String message) { + super(message); + } + + public NoCapablePlatformException(String message, Throwable cause) { + super(message, cause); + } + + public NoCapablePlatformException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java new file mode 100644 index 0000000..7edc9b9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -0,0 +1,218 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.io.ResourceLoader; +import com.sk89q.worldedit.util.translation.TranslationManager; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.registry.Registries; +import org.enginehub.piston.CommandManager; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nullable; + +/** + * Represents a platform that WorldEdit has been implemented for. + * + *

It is strongly recommended that implementations extend from + * {@link AbstractPlatform}.

+ */ +public interface Platform { + + /** + * Return the resource loader. + * + * @return The resource loader + */ + ResourceLoader getResourceLoader(); + + TranslationManager getTranslationManager(); + + /** + * Gets the registry holder. + * + * @return The registry holder + */ + Registries getRegistries(); + + /** + * Gets the Minecraft data version being used by the platform. + * + * @return the data version + */ + int getDataVersion(); + + /** + * Get a DataFixer capable of upgrading old data. + * + * @return a data fixer, or null if not supported by this platform + */ + DataFixer getDataFixer(); + + /** + * Checks if a mob type is valid. + * + * @param type The mob type name to check + * @return Whether the name is a valid mod type + */ + boolean isValidMobType(String type); + + /** + * Reload WorldEdit configuration. + */ + void reload(); + + /** + * Schedules the given {@code task} to be invoked once every + * {@code period} ticks after an initial delay of {@code delay} ticks. + * + * @param delay Delay in server ticks before executing first repeat + * @param period Period in server ticks of the task + * @param task Task to be executed + * @return Task id number (-1 if scheduling failed) + */ + int schedule(long delay, long period, Runnable task); + + /** + * Get the watchdog service. + * + * @return the watchdog service, or {@code null} if none + */ + default @Nullable Watchdog getWatchdog() { + return null; + } + + /** + * Get a list of available or loaded worlds. + * + * @return a list of worlds + */ + List getWorlds(); + + /** + * Create a duplicate of the given player. + * + *

The given player may have been provided by a different platform.

+ * + * @param player the player to match + * @return a matched player, otherwise null + */ + @Nullable Player matchPlayer(Player player); + + /** + * Create a duplicate of the given world. + * + *

The given world may have been provided by a different platform.

+ * + * @param world the world to match + * @return a matched world, otherwise null + */ + @Nullable World matchWorld(World world); + + /** + * Register the commands contained within the given command manager. + * + *

+ * This method should be ignored if the platform offers a command registration event. + *

+ * + * @param commandManager the command manager + */ + void registerCommands(CommandManager commandManager); + + /** + * Register game hooks. + * + * @deprecated Call {@link #setGameHooksEnabled(boolean)} with {@code true} instead + */ + @Deprecated + default void registerGameHooks() { + setGameHooksEnabled(true); + } + + /** + * Set if the game hooks are enabled for this platform. + */ + void setGameHooksEnabled(boolean enabled); + + /** + * Get the configuration from this platform. + * + * @return the configuration + */ + LocalConfiguration getConfiguration(); + + /** + * Get the version of WorldEdit that this platform provides. + * + *

This version should match WorldEdit releases because it may be + * checked to match.

+ * + * @return the version + */ + String getVersion(); + + /** + * Get a friendly name of the platform. + * + *

The name can be anything (reasonable). An example name may be + * "Bukkit" or "Forge".

+ * + * @return the platform name + */ + String getPlatformName(); + + /** + * Get the version of the platform, which can be anything. + * + * @return the platform version + */ + String getPlatformVersion(); + + /** + * Get a map of advertised capabilities of this platform, where each key + * in the given map is a supported capability and the respective value + * indicates the preference for this platform for that given capability. + * + * @return a map of capabilities + */ + Map getCapabilities(); + + /** + * Get a set of {@link SideEffect}s supported by this platform. + * + * @return A set of supported side effects + */ + Set getSupportedSideEffects(); + + /** + * Get the number of ticks since the server started. + * On some platforms this value may be an approximation based on the JVM run time. + * + * @return The number of ticks since the server started. + */ + long getTickCount(); +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java new file mode 100644 index 0000000..1283795 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -0,0 +1,579 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.command.*; +import com.sk89q.worldedit.command.argument.*; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.command.util.SubCommandPermissionCondition; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.event.platform.CommandEvent; +import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.annotation.OptionalArg; +import com.sk89q.worldedit.internal.annotation.Selection; +import com.sk89q.worldedit.internal.command.CommandArgParser; +import com.sk89q.worldedit.internal.command.CommandLoggingHandler; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; +import com.sk89q.worldedit.internal.command.exception.WorldEditExceptionConverter; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.util.Substring; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.eventbus.Subscribe; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.logging.DynamicStreamHandler; +import com.sk89q.worldedit.util.logging.LogFormat; +import com.sk89q.worldedit.world.World; +import org.apache.logging.log4j.Logger; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverters; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.CommandExecutionException; +import org.enginehub.piston.exception.ConditionFailedException; +import org.enginehub.piston.exception.UsageException; +import org.enginehub.piston.gen.CommandRegistration; +import org.enginehub.piston.impl.CommandManagerServiceImpl; +import org.enginehub.piston.inject.*; +import org.enginehub.piston.part.SubCommandPart; +import org.enginehub.piston.suggestion.Suggestion; +import org.enginehub.piston.util.HelpGenerator; +import org.enginehub.piston.util.ValueProvider; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.logging.FileHandler; +import java.util.logging.Level; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Handles the registration and invocation of commands. + * + *

This class is primarily for internal usage.

+ */ +public final class PlatformCommandManager { + + public static final Pattern COMMAND_CLEAN_PATTERN = Pattern.compile("^[/]+"); + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final java.util.logging.Logger COMMAND_LOG = + java.util.logging.Logger.getLogger("com.sk89q.worldedit.CommandLog"); + + private final WorldEdit worldEdit; + private final PlatformManager platformManager; + private final CommandManagerServiceImpl commandManagerService; + private final CommandManager commandManager; + private final InjectedValueStore globalInjectedValues; + private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler(); + private final WorldEditExceptionConverter exceptionConverter; + private final CommandRegistrationHandler registration; + + /** + * Create a new instance. + * + * @param worldEdit the WorldEdit instance + */ + PlatformCommandManager(final WorldEdit worldEdit, PlatformManager platformManager) { + checkNotNull(worldEdit); + checkNotNull(platformManager); + this.worldEdit = worldEdit; + this.platformManager = platformManager; + this.exceptionConverter = new WorldEditExceptionConverter(worldEdit); + this.commandManagerService = new CommandManagerServiceImpl(); + this.commandManager = commandManagerService.newCommandManager(); + this.globalInjectedValues = MapBackedValueStore.create(); + this.registration = new CommandRegistrationHandler( + ImmutableList.of( + new CommandLoggingHandler(worldEdit, COMMAND_LOG) + )); + // setup separate from main constructor + // ensures that everything is definitely assigned + initialize(); + } + + private void initialize() { + // Register this instance for command events + worldEdit.getEventBus().register(this); + + // Setup the logger + COMMAND_LOG.addHandler(dynamicHandler); + + // Set up the commands manager + registerAlwaysInjectedValues(); + registerArgumentConverters(); + registerAllCommands(); + } + + private void registerArgumentConverters() { + DirectionVectorConverter.register(worldEdit, commandManager); + DirectionConverter.register(worldEdit, commandManager); + FactoryConverter.register(worldEdit, commandManager); + for (int count = 2; count <= 3; count++) { + commandManager.registerConverter(Key.of(double.class, Annotations.radii(count)), + CommaSeparatedValuesConverter.wrapAndLimit(ArgumentConverters.get( + TypeToken.of(double.class) + ), count) + ); + } + VectorConverter.register(commandManager); + Chunk3dVectorConverter.register(commandManager); + EnumConverter.register(commandManager); + RegistryConverter.register(commandManager); + ZonedDateTimeConverter.register(commandManager); + BooleanConverter.register(commandManager); + EntityRemoverConverter.register(commandManager); + RegionFactoryConverter.register(commandManager); + WorldConverter.register(commandManager); + SideEffectConverter.register(commandManager); + HeightConverter.register(commandManager); + OffsetConverter.register(worldEdit, commandManager); + } + + private void registerAlwaysInjectedValues() { + globalInjectedValues.injectValue(Key.of(Region.class, Selection.class), + context -> { + LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("No LocalSession")); + return context.injectedValue(Key.of(World.class)) + .map(world -> { + try { + return localSession.getSelection(world); + } catch (IncompleteRegionException e) { + exceptionConverter.convert(e); + throw new AssertionError("Should have thrown a new exception.", e); + } + }); + }); + globalInjectedValues.injectValue(Key.of(EditSession.class), + context -> { + LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("No LocalSession")); + return context.injectedValue(Key.of(Actor.class)) + .map(actor -> { + EditSession editSession = localSession.createEditSession(actor); + editSession.enableStandardMode(); + return editSession; + }); + }); + globalInjectedValues.injectValue(Key.of(World.class), + context -> { + LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("No LocalSession")); + return context.injectedValue(Key.of(Actor.class)) + .map(actor -> { + try { + if (localSession.hasWorldOverride()) { + return localSession.getWorldOverride(); + } else if (actor instanceof Locatable && ((Locatable) actor).getExtent() instanceof World) { + return (World) ((Locatable) actor).getExtent(); + } else { + throw new MissingWorldException(); + } + } catch (MissingWorldException e) { + exceptionConverter.convert(e); + throw new AssertionError("Should have thrown a new exception.", e); + } + }); + }); + } + + /** + * Internal use only. + */ + public void registerSubCommands(String name, List aliases, String desc, + CommandRegistration registration, CI instance) { + registerSubCommands(name, aliases, desc, registration, instance, m -> { + }); + } + + private void registerSubCommands(String name, List aliases, String desc, + CommandRegistration registration, CI instance, + Consumer additionalConfig) { + commandManager.register(name, cmd -> { + cmd.aliases(aliases); + cmd.description(TextComponent.of(desc)); + cmd.action(Command.Action.NULL_ACTION); + + CommandManager manager = commandManagerService.newCommandManager(); + this.registration.register( + manager, + registration, + instance + ); + additionalConfig.accept(manager); + + final List subCommands = manager.getAllCommands().collect(Collectors.toList()); + cmd.addPart(SubCommandPart.builder(TranslatableComponent.of("worldedit.argument.action"), + TextComponent.of("Sub-command to run.")) + .withCommands(subCommands) + .required() + .build()); + + cmd.condition(new SubCommandPermissionCondition.Generator(subCommands).build()); + }); + } + + private void registerAllCommands() { + registerSubCommands( + "schematic", + ImmutableList.of("schem", "/schematic", "/schem"), + "Schematic commands for saving/loading areas", + SchematicCommandsRegistration.builder(), + new SchematicCommands(worldEdit) + ); + registerSubCommands( + "snapshot", + ImmutableList.of("snap"), + "Snapshot commands for restoring backups", + SnapshotCommandsRegistration.builder(), + new SnapshotCommands(worldEdit) + ); + registerSubCommands( + "superpickaxe", + ImmutableList.of("pickaxe", "sp"), + "Super-pickaxe commands", + SuperPickaxeCommandsRegistration.builder(), + new SuperPickaxeCommands(worldEdit) + ); + registerSubCommands( + "brush", + ImmutableList.of("br", "/brush", "/br"), + "Brushing commands", + BrushCommandsRegistration.builder(), + new BrushCommands(worldEdit), + manager -> { + PaintBrushCommands.register(commandManagerService, manager, registration); + ApplyBrushCommands.register(commandManagerService, manager, registration); + } + ); + registerSubCommands( + "worldedit", + ImmutableList.of("we"), + "WorldEdit commands", + WorldEditCommandsRegistration.builder(), + new WorldEditCommands(worldEdit) + ); + this.registration.register( + commandManager, + BiomeCommandsRegistration.builder(), + new BiomeCommands() + ); + this.registration.register( + commandManager, + ChunkCommandsRegistration.builder(), + new ChunkCommands(worldEdit) + ); + this.registration.register( + commandManager, + ClipboardCommandsRegistration.builder(), + new ClipboardCommands() + ); + GeneralCommands.register( + registration, + commandManager, + commandManagerService, + worldEdit + ); + this.registration.register( + commandManager, + GenerationCommandsRegistration.builder(), + new GenerationCommands(worldEdit) + ); + this.registration.register( + commandManager, + HistoryCommandsRegistration.builder(), + new HistoryCommands(worldEdit) + ); + this.registration.register( + commandManager, + NavigationCommandsRegistration.builder(), + new NavigationCommands(worldEdit) + ); + this.registration.register( + commandManager, + RegionCommandsRegistration.builder(), + new RegionCommands() + ); + this.registration.register( + commandManager, + ScriptingCommandsRegistration.builder(), + new ScriptingCommands(worldEdit) + ); + this.registration.register( + commandManager, + SelectionCommandsRegistration.builder(), + new SelectionCommands(worldEdit) + ); + ExpandCommands.register(registration, commandManager, commandManagerService); + this.registration.register( + commandManager, + SnapshotUtilCommandsRegistration.builder(), + new SnapshotUtilCommands(worldEdit) + ); + ToolCommands.register(registration, commandManager, commandManagerService, worldEdit); + this.registration.register( + commandManager, + ToolUtilCommandsRegistration.builder(), + new ToolUtilCommands(worldEdit) + ); + this.registration.register( + commandManager, + UtilityCommandsRegistration.builder(), + new UtilityCommands(worldEdit) + ); + } + + public ExceptionConverter getExceptionConverter() { + return exceptionConverter; + } + + void registerCommandsWith(Platform platform) { + LOGGER.info("Registering commands with " + platform.getClass().getCanonicalName()); + + LocalConfiguration config = platform.getConfiguration(); + boolean logging = config.logCommands; + String path = config.logFile; + + // Register log + if (!logging || path.isEmpty()) { + dynamicHandler.setHandler(null); + COMMAND_LOG.setLevel(Level.OFF); + } else { + File file = new File(config.getWorkingDirectory(), path); + COMMAND_LOG.setLevel(Level.ALL); + + LOGGER.info("Logging WorldEdit commands to " + file.getAbsolutePath()); + + try { + dynamicHandler.setHandler(new FileHandler(file.getAbsolutePath(), true)); + } catch (IOException e) { + LOGGER.warn("Could not use command log file " + path + ": " + e.getMessage()); + } + + dynamicHandler.setFormatter(new LogFormat(config.logFormat)); + } + + platform.registerCommands(commandManager); + } + + void removeCommands() { + dynamicHandler.setHandler(null); + } + + private Stream parseArgs(String input) { + return CommandArgParser.forArgString(input.substring(1)).parseArgs(); + } + + @Subscribe + public void handleCommand(CommandEvent event) { + Request.reset(); + + Actor actor = platformManager.createProxyActor(event.getActor()); + String[] split = parseArgs(event.getArguments()) + .map(Substring::getSubstring) + .toArray(String[]::new); + + // No command found! + if (!commandManager.containsCommand(split[0])) { + return; + } + + LocalSession session = worldEdit.getSessionManager().get(actor); + Request.request().setSession(session); + if (actor instanceof Entity) { + Extent extent = ((Entity) actor).getExtent(); + if (extent instanceof World) { + Request.request().setWorld(((World) extent)); + } + } + LocalConfiguration config = worldEdit.getConfiguration(); + + MemoizingValueAccess context = initializeInjectedValues(event::getArguments, actor); + + long start = System.currentTimeMillis(); + + try { + // This is a bit of a hack, since the call method can only throw CommandExceptions + // everything needs to be wrapped at least once. Which means to handle all WorldEdit + // exceptions without writing a hook into every dispatcher, we need to unwrap these + // exceptions and rethrow their converted form, if their is one. + try { + commandManager.execute(context, ImmutableList.copyOf(split)); + } catch (Throwable t) { + // Use the exception converter to convert the exception if any of its causes + // can be converted, otherwise throw the original exception + Throwable next = t; + do { + exceptionConverter.convert(next); + next = next.getCause(); + } while (next != null); + + throw t; + } + } catch (ConditionFailedException e) { + if (e.getCondition() instanceof PermissionCondition) { + actor.printError(TranslatableComponent.of("worldedit.command.permissions")); + } else { + actor.print(e.getRichMessage()); + } + } catch (UsageException e) { + actor.print(TextComponent.builder("") + .color(TextColor.RED) + .append(e.getRichMessage()) + .build()); + ImmutableList cmd = e.getCommands(); + if (!cmd.isEmpty()) { + actor.printError( + TranslatableComponent.of("worldedit.error.incorrect-usage", + HelpGenerator.create(e.getCommandParseResult()).getUsage()) + ); + } + } catch (CommandExecutionException e) { + handleUnknownException(actor, e.getCause()); + } catch (CommandException e) { + actor.printError(e.getRichMessage()); + } catch (Throwable t) { + handleUnknownException(actor, t); + } finally { + Optional editSessionOpt = + context.snapshotMemory().injectedValue(Key.of(EditSession.class)); + + if (editSessionOpt.isPresent()) { + EditSession editSession = editSessionOpt.get(); + session.remember(editSession); + editSession.close(); + + if (config.profile) { + long time = System.currentTimeMillis() - start; + double timeS = (time / 1000.0); + int changed = editSession.getBlockChangeCount(); + double throughput = timeS == 0 ? changed : changed / timeS; + actor.printDebug(TranslatableComponent.of( + "worldedit.command.time-elapsed", + TextComponent.of(timeS), + TextComponent.of(changed), + TextComponent.of(Math.round(throughput)) + )); + } + + worldEdit.flushBlockBag(actor, editSession); + } + Request.reset(); + } + + event.setCancelled(true); + } + + private MemoizingValueAccess initializeInjectedValues(Arguments arguments, Actor actor) { + InjectedValueStore store = MapBackedValueStore.create(); + store.injectValue(Key.of(Actor.class), ValueProvider.constant(actor)); + if (actor instanceof Player) { + store.injectValue(Key.of(Player.class), ValueProvider.constant((Player) actor)); + store.injectValue(Key.of(Player.class, OptionalArg.class), ValueProvider.constant((Player) actor)); + } else { + store.injectValue(Key.of(Player.class), context -> { + throw new CommandException(TranslatableComponent.of("worldedit.command.player-only"), ImmutableList.of()); + }); + } + store.injectValue(Key.of(Arguments.class), ValueProvider.constant(arguments)); + store.injectValue(Key.of(LocalSession.class), + context -> { + LocalSession localSession = worldEdit.getSessionManager().get(actor); + localSession.tellVersion(actor); + return Optional.of(localSession); + }); + + return MemoizingValueAccess.wrap( + MergedValueAccess.of(store, globalInjectedValues) + ); + } + + private void handleUnknownException(Actor actor, Throwable t) { + actor.printError(TranslatableComponent.of("worldedit.command.error.report")); + actor.print(TextComponent.of(t.getClass().getName() + ": " + t.getMessage())); + LOGGER.error("An unexpected error while handling a WorldEdit command", t); + } + + @Subscribe + public void handleCommandSuggestion(CommandSuggestionEvent event) { + try { + String arguments = event.getArguments(); + List split = parseArgs(arguments).collect(Collectors.toList()); + List argStrings = split.stream() + .map(Substring::getSubstring) + .collect(Collectors.toList()); + MemoizingValueAccess access = initializeInjectedValues(() -> arguments, event.getActor()); + ImmutableSet suggestions; + try { + suggestions = commandManager.getSuggestions(access, argStrings); + } catch (Throwable t) { // catch errors which are *not* command exceptions generated by parsers/suggesters + if (!(t instanceof CommandException)) { + LOGGER.debug("Unexpected error occurred while generating suggestions for input: " + arguments, t); + return; + } + throw t; + } + + event.setSuggestions(suggestions.stream() + .map(suggestion -> { + int noSlashLength = arguments.length() - 1; + Substring original = suggestion.getReplacedArgument() == split.size() + ? Substring.from(arguments, noSlashLength, noSlashLength) + : split.get(suggestion.getReplacedArgument()); + // increase original points by 1, for removed `/` in `parseArgs` + return Substring.wrap( + suggestion.getSuggestion(), + original.getStart() + 1, + original.getEnd() + 1 + ); + }).collect(Collectors.toList())); + } catch (ConditionFailedException e) { + if (e.getCondition() instanceof PermissionCondition) { + event.setSuggestions(new ArrayList<>()); + } + } + } + + /** + * Get the command manager instance. + * + * @return the command manager + */ + public CommandManager getCommandManager() { + return commandManager; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java new file mode 100644 index 0000000..34e520a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -0,0 +1,442 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.tool.*; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.event.platform.*; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.eventbus.Subscribe; +import com.sk89q.worldedit.world.World; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Manages registered {@link Platform}s for WorldEdit. Platforms are + * implementations of WorldEdit. + * + *

This class is thread-safe.

+ */ +public class PlatformManager { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final WorldEdit worldEdit; + private final PlatformCommandManager platformCommandManager; + private final List platforms = new ArrayList<>(); + private final Map preferences = new EnumMap<>(Capability.class); + private @Nullable String firstSeenVersion; + private final AtomicBoolean initialized = new AtomicBoolean(); + private final AtomicBoolean configured = new AtomicBoolean(); + + /** + * Create a new platform manager. + * + * @param worldEdit the WorldEdit instance + */ + public PlatformManager(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + this.platformCommandManager = new PlatformCommandManager(worldEdit, this); + + // Register this instance for events + worldEdit.getEventBus().register(this); + } + + /** + * Register a platform with WorldEdit. + * + * @param platform the platform + */ + public synchronized void register(Platform platform) { + checkNotNull(platform); + + LOGGER.info("Got request to register " + platform.getClass() + " with WorldEdit [" + super.toString() + "]"); + + // Just add the platform to the list of platforms: we'll pick favorites + // once all the platforms have been loaded + platforms.add(platform); + + // Make sure that versions are in sync + if (firstSeenVersion != null) { + if (!firstSeenVersion.equals(platform.getVersion())) { + LOGGER.warn("Multiple ports of WorldEdit are installed but they report different versions ({} and {}). " + + "If these two versions are truly different, then you may run into unexpected crashes and errors.", + firstSeenVersion, platform.getVersion()); + } + } else { + firstSeenVersion = platform.getVersion(); + } + } + + /** + * Unregister a platform from WorldEdit. + * + *

If the platform has been chosen for any capabilities, then a new + * platform will be found.

+ * + * @param platform the platform + */ + public synchronized boolean unregister(Platform platform) { + checkNotNull(platform); + + boolean removed = platforms.remove(platform); + + if (removed) { + LOGGER.info("Unregistering " + platform.getClass().getCanonicalName() + " from WorldEdit"); + + boolean choosePreferred = false; + + // Check whether this platform was chosen to be the preferred one + // for any capability and be sure to remove it + Iterator> it = preferences.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + if (entry.getValue().equals(platform)) { + entry.getKey().uninitialize(this, entry.getValue()); + it.remove(); + choosePreferred = true; // Have to choose new favorites + } + } + + if (choosePreferred) { + choosePreferred(); + } + } + + return removed; + } + + /** + * Get the preferred platform for handling a certain capability. Throws if none are available. + * + * @param capability the capability + * @return the platform + * @throws NoCapablePlatformException thrown if no platform is capable + */ + public synchronized Platform queryCapability(Capability capability) throws NoCapablePlatformException { + Platform platform = preferences.get(checkNotNull(capability)); + if (platform != null) { + return platform; + } else { + if (preferences.isEmpty()) { + // Not all platforms registered, this is being called too early! + throw new NoCapablePlatformException( + "Not all platforms have been registered yet!" + + " Please wait until WorldEdit is initialized." + ); + } + throw new NoCapablePlatformException("No platform was found supporting " + capability.name()); + } + } + + /** + * Choose preferred platforms and perform necessary initialization. + */ + private synchronized void choosePreferred() { + for (Capability capability : Capability.values()) { + Platform preferred = findMostPreferred(capability); + if (preferred != null) { + Platform oldPreferred = preferences.put(capability, preferred); + // only (re)initialize if it changed + if (preferred != oldPreferred) { + // uninitialize if needed + if (oldPreferred != null) { + capability.uninitialize(this, oldPreferred); + } + capability.initialize(this, preferred); + } + } + } + + // Fire configuration event + if (preferences.containsKey(Capability.CONFIGURATION) && configured.compareAndSet(false, true)) { + worldEdit.getEventBus().post(new ConfigurationLoadEvent(queryCapability(Capability.CONFIGURATION).getConfiguration())); + } + } + + /** + * Find the most preferred platform for a given capability from the list of + * platforms. This does not use the map of preferred platforms. + * + * @param capability the capability + * @return the most preferred platform, or null if no platform was found + */ + private synchronized @Nullable Platform findMostPreferred(Capability capability) { + Platform preferred = null; + Preference highest = null; + + for (Platform platform : platforms) { + Preference preference = platform.getCapabilities().get(capability); + if (preference != null && (highest == null || preference.isPreferredOver(highest))) { + preferred = platform; + highest = preference; + } + } + + return preferred; + } + + /** + * Get a list of loaded platforms. + * + *

The returned list is a copy of the original and is mutable.

+ * + * @return a list of platforms + */ + public synchronized List getPlatforms() { + return new ArrayList<>(platforms); + } + + /** + * Given a world, possibly return the same world but using a different + * platform preferred for world editing operations. + * + * @param base the world to match + * @return the preferred world, if one was found, otherwise the given world + */ + public World getWorldForEditing(World base) { + checkNotNull(base); + World match = queryCapability(Capability.WORLD_EDITING).matchWorld(base); + return match != null ? match : base; + } + + /** + * Given an actor, return a new one that may use a different platform + * for permissions and world editing. + * + * @param base the base actor to match + * @return a new delegate actor + */ + @SuppressWarnings("unchecked") + public T createProxyActor(T base) { + checkNotNull(base); + + if (base instanceof Player) { + Player player = (Player) base; + + Player permActor = queryCapability(Capability.PERMISSIONS).matchPlayer(player); + if (permActor == null) { + permActor = player; + } + + Player cuiActor = queryCapability(Capability.WORLDEDIT_CUI).matchPlayer(player); + if (cuiActor == null) { + cuiActor = player; + } + + return (T) new PlayerProxy(player, permActor, cuiActor, getWorldForEditing(player.getWorld())); + } else { + return base; + } + } + + /** + * Get the command manager. + * + * @return the command manager + */ + public PlatformCommandManager getPlatformCommandManager() { + return platformCommandManager; + } + + /** + * Get the current configuration. + * + *

If no platform has been registered yet, then a default configuration + * will be returned.

+ * + * @return the configuration + */ + public LocalConfiguration getConfiguration() { + return queryCapability(Capability.CONFIGURATION).getConfiguration(); + } + + /** + * Get the current supported {@link SideEffect}s. + * + * @return the supported side effects + * @throws NoCapablePlatformException thrown if no platform is capable + */ + public Collection getSupportedSideEffects() { + return queryCapability(Capability.WORLD_EDITING).getSupportedSideEffects(); + } + + /** + * Get the initialized state of the Platform. + * {@return if the platform manager is initialized} + */ + public boolean isInitialized() { + return initialized.get(); + } + + /** + * You shouldn't have been calling this anyways, but this is now deprecated. Either don't + * fire this event at all, or fire the new event via the event bus if you're a platform. + */ + @Deprecated + public void handlePlatformReady(@SuppressWarnings("unused") PlatformReadyEvent event) { + handlePlatformsRegistered(new PlatformsRegisteredEvent()); + } + + /** + * Internal, do not call. + */ + @Subscribe + public void handlePlatformsRegistered(PlatformsRegisteredEvent event) { + choosePreferred(); + if (initialized.compareAndSet(false, true)) { + worldEdit.getEventBus().post(new PlatformInitializeEvent()); + } + } + + /** + * Internal, do not call. + */ + @Subscribe + public void handleNewPlatformReady(PlatformReadyEvent event) { + preferences.forEach((cap, platform) -> cap.ready(this, platform)); + } + + /** + * Internal, do not call. + */ + @Subscribe + public void handleNewPlatformUnready(PlatformUnreadyEvent event) { + preferences.forEach((cap, platform) -> cap.unready(this, platform)); + } + + @Subscribe + public void handleBlockInteract(BlockInteractEvent event) { + // Create a proxy actor with a potentially different world for + // making changes to the world + Actor actor = createProxyActor(event.getCause()); + + Location location = event.getLocation(); + + // At this time, only handle interaction from players + if (!(actor instanceof Player)) { + return; + } + Player player = (Player) actor; + LocalSession session = worldEdit.getSessionManager().get(actor); + + Request.reset(); + Request.request().setSession(session); + Request.request().setWorld(player.getWorld()); + + try { + if (event.getType() == Interaction.HIT) { + // superpickaxe is special because its primary interaction is a left click, not a right click + // in addition, it is implicitly bound to all pickaxe items, not just a single tool item + if (session.hasSuperPickAxe() && player.isHoldingPickAxe()) { + final BlockTool superPickaxe = session.getSuperPickaxe(); + if (superPickaxe != null && superPickaxe.canUse(player)) { + if (superPickaxe.actPrimary(queryCapability(Capability.WORLD_EDITING), + getConfiguration(), player, session, location, event.getFace())) { + event.setCancelled(true); + } + return; + } + } + + Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + if (tool instanceof DoubleActionBlockTool && tool.canUse(player)) { + if (((DoubleActionBlockTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), + getConfiguration(), player, session, location, event.getFace())) { + event.setCancelled(true); + } + } + + } else if (event.getType() == Interaction.OPEN) { + Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + if (tool instanceof BlockTool && tool.canUse(player)) { + if (((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), + getConfiguration(), player, session, location, event.getFace())) { + event.setCancelled(true); + } + } + } + } finally { + Request.reset(); + } + } + + @Subscribe + public void handlePlayerInput(PlayerInputEvent event) { + // Create a proxy actor with a potentially different world for + // making changes to the world + Player player = createProxyActor(event.getPlayer()); + LocalSession session = worldEdit.getSessionManager().get(player); + Request.reset(); + Request.request().setSession(session); + Request.request().setWorld(player.getWorld()); + + try { + switch (event.getInputType()) { + case PRIMARY: { + Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + if (tool instanceof DoubleActionTraceTool && tool.canUse(player)) { + if (((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), + getConfiguration(), player, session)) { + event.setCancelled(true); + } + return; + } + + break; + } + + case SECONDARY: { + Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + if (tool instanceof TraceTool && tool.canUse(player)) { + if (((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), + getConfiguration(), player, session)) { + event.setCancelled(true); + } + return; + } + + break; + } + + default: + break; + } + } finally { + Request.reset(); + } + } + + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java b/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java new file mode 100644 index 0000000..cdc7f47 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java @@ -0,0 +1,201 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.session.SessionKey; +import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.Location; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.gamemode.GameMode; + +import javax.annotation.Nullable; +import java.util.Locale; +import java.util.UUID; + +import static com.google.common.base.Preconditions.checkNotNull; + +class PlayerProxy extends AbstractPlayerActor { + + private final Player basePlayer; + private final Actor permActor; + private final Actor cuiActor; + private final World world; + + PlayerProxy(Player basePlayer, Actor permActor, Actor cuiActor, World world) { + checkNotNull(basePlayer); + checkNotNull(permActor); + checkNotNull(cuiActor); + checkNotNull(world); + this.basePlayer = basePlayer; + this.permActor = permActor; + this.cuiActor = cuiActor; + this.world = world; + } + + @Override + public UUID getUniqueId() { + return basePlayer.getUniqueId(); + } + + @Override + public BaseItemStack getItemInHand(HandSide handSide) { + return basePlayer.getItemInHand(handSide); + } + + @Override + public void giveItem(BaseItemStack itemStack) { + basePlayer.giveItem(itemStack); + } + + @Override + public BlockBag getInventoryBlockBag() { + return basePlayer.getInventoryBlockBag(); + } + + @Override + public String getName() { + return basePlayer.getName(); + } + + @Override + public String getDisplayName() { + return basePlayer.getDisplayName(); + } + + @Override + public BaseEntity getState() { + throw new UnsupportedOperationException("Can't getState() on a player"); + } + + @Override + public Location getLocation() { + return basePlayer.getLocation(); + } + + @Override + public boolean setLocation(Location location) { + return basePlayer.setLocation(location); + } + + @Override + public boolean trySetPosition(Vector3 pos, float pitch, float yaw) { + return basePlayer.trySetPosition(pos, pitch, yaw); + } + + @Override + public World getWorld() { + return world; + } + + @Override + @Deprecated + public void printRaw(String msg) { + basePlayer.print(TextComponent.of(msg)); + } + + @Override + @Deprecated + public void printDebug(String msg) { + basePlayer.printDebug(TextComponent.of(msg)); + } + + @Override + @Deprecated + public void print(String msg) { + basePlayer.printInfo(TextComponent.of(msg)); + } + + @Override + @Deprecated + public void printError(String msg) { + basePlayer.printError(TextComponent.of(msg)); + } + + @Override + public void print(Component component) { + basePlayer.print(component); + } + + @Override + public String[] getGroups() { + return permActor.getGroups(); + } + + @Override + public boolean hasPermission(String perm) { + return permActor.hasPermission(perm); + } + + @Override + public void dispatchCUIEvent(CUIEvent event) { + cuiActor.dispatchCUIEvent(event); + } + + @Override + public void sendAnnouncements() { + basePlayer.sendAnnouncements(); + } + + @Nullable + @Override + public T getFacet(Class cls) { + return basePlayer.getFacet(cls); + } + + @Override + public SessionKey getSessionKey() { + return basePlayer.getSessionKey(); + } + + @Override + public GameMode getGameMode() { + return basePlayer.getGameMode(); + } + + @Override + public void setGameMode(GameMode gameMode) { + basePlayer.setGameMode(gameMode); + } + + @Override + public > void sendFakeBlock(BlockVector3 pos, B block) { + basePlayer.sendFakeBlock(pos, block); + } + + @Override + public void floatAt(int x, int y, int z, boolean alwaysGlass) { + basePlayer.floatAt(x, y, z, alwaysGlass); + } + + @Override + public Locale getLocale() { + return basePlayer.getLocale(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/Preference.java b/src/main/java/com/sk89q/worldedit/extension/platform/Preference.java new file mode 100644 index 0000000..26c8de2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/Preference.java @@ -0,0 +1,59 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Indicates the preference of a platform for a particular + * {@link Capability}. + */ +public enum Preference { + + /** + * Indicates that the platform should be preferred for a given capability. + */ + PREFERRED, + + /** + * Indicates that preference for a platform is neutral for a given + * capability. + */ + NORMAL, + + /** + * Indicates that there should not be a preference for the platform for + * a given capability. + */ + PREFER_OTHERS; + + /** + * Returns whether this given preference is preferred over the given + * other preference. + * + * @param other the other preference + * @return true if this preference is greater + */ + public boolean isPreferredOver(Preference other) { + checkNotNull(other); + return ordinal() < other.ordinal(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java b/src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java new file mode 100644 index 0000000..63a230e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java @@ -0,0 +1,29 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform; + +/** + * Interface to a {@link Platform}'s watchdog service. + */ +public interface Watchdog { + + void tick(); + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/permission/ActorSelectorLimits.java b/src/main/java/com/sk89q/worldedit/extension/platform/permission/ActorSelectorLimits.java new file mode 100644 index 0000000..48c342f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/permission/ActorSelectorLimits.java @@ -0,0 +1,86 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform.permission; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ActorSelectorLimits implements SelectorLimits { + + private final LocalConfiguration configuration; + private final Actor actor; + + public ActorSelectorLimits(LocalConfiguration configuration, Actor actor) { + checkNotNull(configuration); + checkNotNull(actor); + + this.configuration = configuration; + this.actor = actor; + } + + @Override + public Optional getPolygonVertexLimit() { + int limit; + + if (actor.hasPermission(OverridePermissions.NO_LIMITS) || configuration.maxPolygonalPoints < 0) { + limit = configuration.defaultMaxPolygonalPoints; + } else if (configuration.defaultMaxPolygonalPoints < 0) { + limit = configuration.maxPolygonalPoints; + } else { + limit = Math.min(configuration.defaultMaxPolygonalPoints, configuration.maxPolygonalPoints); + } + + if (limit > 0) { + return Optional.of(limit); + } else { + return Optional.empty(); + } + } + + @Override + public Optional getPolyhedronVertexLimit() { + int limit; + + if (actor.hasPermission(OverridePermissions.NO_LIMITS) || configuration.maxPolyhedronPoints < 0) { + limit = configuration.defaultMaxPolyhedronPoints; + } else if (configuration.defaultMaxPolyhedronPoints < 0) { + limit = configuration.maxPolyhedronPoints; + } else { + limit = Math.min(configuration.defaultMaxPolyhedronPoints, configuration.maxPolyhedronPoints); + } + + if (limit > 0) { + return Optional.of(limit); + } else { + return Optional.empty(); + } + } + + public static ActorSelectorLimits forActor(Actor actor) { + return new ActorSelectorLimits(WorldEdit.getInstance().getConfiguration(), actor); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/permission/OverridePermissions.java b/src/main/java/com/sk89q/worldedit/extension/platform/permission/OverridePermissions.java new file mode 100644 index 0000000..e445482 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/platform/permission/OverridePermissions.java @@ -0,0 +1,32 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extension.platform.permission; + +/** + * Standard override permissions. + */ +public final class OverridePermissions { + + public static final String NO_LIMITS = "worldedit.limit.unrestricted"; + + private OverridePermissions() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java b/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java new file mode 100644 index 0000000..dbcb53c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java @@ -0,0 +1,102 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; +import java.util.Optional; + +/** + * Base extent class for buffering changes between {@link #setBlock(BlockVector3, BlockStateHolder)} + * and the delegate extent. This class ensures that {@link #getBlock(BlockVector3)} is properly + * handled, by returning buffered blocks. + */ +public abstract class AbstractBufferingExtent extends AbstractDelegateExtent { + /** + * Create a new instance. + * + * @param extent the extent + */ + protected AbstractBufferingExtent(Extent extent) { + super(extent); + } + + @Override + public abstract > boolean setBlock(BlockVector3 location, T block) throws WorldEditException; + + protected final > boolean setDelegateBlock(BlockVector3 location, T block) throws WorldEditException { + return super.setBlock(location, block); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + BaseBlock block = getBufferedFullBlock(position); + if (block == null) { + return super.getBlock(position); + } + return block.toImmutableState(); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + BaseBlock block = getBufferedFullBlock(position); + if (block == null) { + return super.getFullBlock(position); + } + return block; + } + + /** + * Gets a block from the buffer. + * + * @deprecated New subclasses should override {@link #getBufferedFullBlock(BlockVector3)} + * instead + */ + @Deprecated + protected Optional getBufferedBlock(BlockVector3 position) { + return Optional.ofNullable(getBufferedFullBlock(position)); + } + + /** + * Gets a block from the buffer, or null if not buffered. + * + * @param position The position + * @return The buffered block, or null + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "getBufferedBlock", + delegateParams = { BlockVector3.class } + ) + @Nullable + protected BaseBlock getBufferedFullBlock(BlockVector3 position) { + DeprecationUtil.checkDelegatingOverride(getClass()); + return getBufferedBlock(position).orElse(null); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java new file mode 100644 index 0000000..f90cb3c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -0,0 +1,141 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.OperationQueue; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A base class for {@link Extent}s that merely passes extents onto another. + */ +public abstract class AbstractDelegateExtent implements Extent { + + private final Extent extent; + + /** + * Create a new instance. + * + * @param extent the extent + */ + protected AbstractDelegateExtent(Extent extent) { + checkNotNull(extent); + this.extent = extent; + } + + /** + * Get the extent. + * + * @return the extent + */ + public Extent getExtent() { + return extent; + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return extent.getBlock(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return extent.getFullBlock(position); + } + + @Override + public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { + return extent.setBlock(location, block); + } + + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity) { + return extent.createEntity(location, entity); + } + + @Override + public List getEntities() { + return extent.getEntities(); + } + + @Override + public List getEntities(Region region) { + return extent.getEntities(region); + } + + @Override + public boolean fullySupports3DBiomes() { + return extent.fullySupports3DBiomes(); + } + + @Override + public BiomeType getBiome(BlockVector3 position) { + return extent.getBiome(position); + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + return extent.setBiome(position, biome); + } + + @Override + public BlockVector3 getMinimumPoint() { + return extent.getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return extent.getMaximumPoint(); + } + + protected Operation commitBefore() { + return null; + } + + @Override + public final @Nullable Operation commit() { + Operation ours = commitBefore(); + Operation other = extent.commit(); + if (ours != null && other != null) { + return new OperationQueue(ours, other); + } else if (ours != null) { + return ours; + } else if (other != null) { + return other; + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java b/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java new file mode 100644 index 0000000..f309bbf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java @@ -0,0 +1,149 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.history.change.BiomeChange3D; +import com.sk89q.worldedit.history.change.BlockChange; +import com.sk89q.worldedit.history.change.EntityCreate; +import com.sk89q.worldedit.history.change.EntityRemove; +import com.sk89q.worldedit.history.changeset.ChangeSet; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Stores changes to a {@link ChangeSet}. + */ +public class ChangeSetExtent extends AbstractDelegateExtent { + + private final ChangeSet changeSet; + + /** + * Create a new instance. + * + * @param extent the extent + * @param changeSet the change set + */ + public ChangeSetExtent(Extent extent, ChangeSet changeSet) { + super(extent); + checkNotNull(changeSet); + this.changeSet = changeSet; + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + BaseBlock previous = getFullBlock(location); + changeSet.add(new BlockChange(location, previous, block)); + return super.setBlock(location, block); + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + BiomeType previous = getBiome(position); + changeSet.add(new BiomeChange3D(position, previous, biome)); + return super.setBiome(position, biome); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity state) { + Entity entity = super.createEntity(location, state); + if (entity != null) { + changeSet.add(new EntityCreate(location, state, entity)); + } + return entity; + } + + @Override + public List getEntities() { + return wrapEntities(super.getEntities()); + } + + @Override + public List getEntities(Region region) { + return wrapEntities(super.getEntities(region)); + } + + private List wrapEntities(List entities) { + List newList = new ArrayList<>(entities.size()); + for (Entity entity : entities) { + newList.add(new TrackedEntity(entity)); + } + return newList; + } + + private class TrackedEntity implements Entity { + private final Entity entity; + + private TrackedEntity(Entity entity) { + this.entity = entity; + } + + @Override + public BaseEntity getState() { + return entity.getState(); + } + + @Override + public Location getLocation() { + return entity.getLocation(); + } + + @Override + public boolean setLocation(Location location) { + // TODO Add a changeset for this. + return entity.setLocation(location); + } + + @Override + public Extent getExtent() { + return entity.getExtent(); + } + + @Override + public boolean remove() { + Location location = entity.getLocation(); + BaseEntity state = entity.getState(); + boolean success = entity.remove(); + if (state != null && success) { + changeSet.add(new EntityRemove(location, state)); + } + return success; + } + + @Nullable + @Override + public T getFacet(Class cls) { + return entity.getFacet(cls); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/Extent.java b/src/main/java/com/sk89q/worldedit/extent/Extent.java new file mode 100644 index 0000000..2d7ccea --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent; + +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; + +import javax.annotation.Nullable; +import java.util.List; + +/** + * A world, portion of a world, clipboard, or other object that can have blocks + * set or entities placed. + * + * @see InputExtent the get____() portion + * @see OutputExtent the set____() portion + */ +public interface Extent extends InputExtent, OutputExtent { + + /** + * Get the minimum point in the extent. + * + *

If the extent is unbounded, then a large (negative) value may + * be returned.

+ * + * @return the minimum point + */ + BlockVector3 getMinimumPoint(); + + /** + * Get the maximum point in the extent. + * + *

If the extent is unbounded, then a large (positive) value may + * be returned.

+ * + * @return the maximum point + */ + BlockVector3 getMaximumPoint(); + + /** + * Get a list of all entities within the given region. + * + *

If the extent is not wholly loaded (i.e. a world being simulated in the + * game will not have every chunk loaded), then this list may not be + * incomplete.

+ * + * @param region the region in which entities must be contained + * @return a list of entities + */ + List getEntities(Region region); + + /** + * Get a list of all entities. + * + *

If the extent is not wholly loaded (i.e. a world being simulated in the + * game will not have every chunk loaded), then this list may not be + * incomplete.

+ * + * @return a list of entities + */ + List getEntities(); + + /** + * Create an entity at the given location. + * + * @param entity the entity + * @param location the location + * @return a reference to the created entity, or null if the entity could not be created + */ + @Nullable Entity createEntity(Location location, BaseEntity entity); + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/InputExtent.java b/src/main/java/com/sk89q/worldedit/extent/InputExtent.java new file mode 100644 index 0000000..6168f29 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/InputExtent.java @@ -0,0 +1,103 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent; + +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +/** + * Provides the current state of blocks, entities, and so on. + */ +public interface InputExtent { + + /** + * Get a snapshot of the block at the given location. + * + *

If the given position is out of the bounds of the extent, then the behavior + * is undefined (an air block could be returned). However, {@code null} + * should not be returned.

+ * + *

The returned block is immutable and is a snapshot of the block at the time + * of call. It has no position attached to it, so it could be reused in + * {@link Pattern}s and so on.

+ * + * @param position position of the block + * @return the block + */ + BlockState getBlock(BlockVector3 position); + + /** + * Get a immutable snapshot of the block at the given location. + * + * @param position position of the block + * @return the block + */ + BaseBlock getFullBlock(BlockVector3 position); + + /** + * Get the biome at the given location. + * + *

If there is no biome available, then the ocean biome should be + * returned.

+ * + * @param position the (x, z) location to check the biome at + * @return the biome at the location + * @deprecated Biomes in Minecraft are 3D now, use {@link InputExtent#getBiome(BlockVector3)} + */ + @Deprecated + default BiomeType getBiome(BlockVector2 position) { + return getBiome(position.toBlockVector3()); + } + + /** + * Get the biome at the given location. + * + *

+ * If there is no biome available, then the ocean biome should be + * returned. + *

+ * + *

+ * As implementation varies per Minecraft version, this may not exactly get + * this positions biome. On versions prior to 1.15, this will get the entire + * column. On later versions it will get the 4x4x4 cube's biome. + *

+ * + * @param position the (x, y, z) location to check the biome at + * @return the biome at the location + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "getBiome", + delegateParams = { BlockVector2.class } + ) + default BiomeType getBiome(BlockVector3 position) { + DeprecationUtil.checkDelegatingOverride(getClass()); + + return getBiome(position.toBlockVector2()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java b/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java new file mode 100644 index 0000000..1de774a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java @@ -0,0 +1,72 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Requires that all mutating methods pass a given {@link Mask}. + */ +public class MaskingExtent extends AbstractDelegateExtent { + + private Mask mask; + + /** + * Create a new instance. + * + * @param extent the extent + * @param mask the mask + */ + public MaskingExtent(Extent extent, Mask mask) { + super(extent); + checkNotNull(mask); + this.mask = mask; + } + + /** + * Get the mask. + * + * @return the mask + */ + public Mask getMask() { + return mask; + } + + /** + * Set a mask. + * + * @param mask a mask + */ + public void setMask(Mask mask) { + checkNotNull(mask); + this.mask = mask; + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + return mask.test(location) && super.setBlock(location, block); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/NullExtent.java b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java new file mode 100644 index 0000000..da5eae4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/NullExtent.java @@ -0,0 +1,108 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; + +/** + * An extent that returns air blocks for all blocks and does not + * pass on any changes. + */ +public class NullExtent implements Extent { + + @Override + public BlockVector3 getMinimumPoint() { + return BlockVector3.ZERO; + } + + @Override + public BlockVector3 getMaximumPoint() { + return BlockVector3.ZERO; + } + + @Override + public List getEntities(Region region) { + return Collections.emptyList(); + } + + @Override + public List getEntities() { + return Collections.emptyList(); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + return null; + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return BlockTypes.AIR.getDefaultState(); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return getBlock(position).toBaseBlock(); + } + + @Override + public BiomeType getBiome(BlockVector3 position) { + return BiomeTypes.THE_VOID; + } + + @Override + public > boolean setBlock(BlockVector3 position, B block) throws WorldEditException { + return false; + } + + @Override + public boolean fullySupports3DBiomes() { + return false; + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + return false; + } + + @Nullable + @Override + public Operation commit() { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java b/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java new file mode 100644 index 0000000..dc1febd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java @@ -0,0 +1,119 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; + +/** + * Accepts block and entity changes. + */ +public interface OutputExtent { + + /** + * Change the block at the given location to the given block. The operation may + * not tie the given {@link BlockStateHolder} to the world, so future changes to the + * {@link BlockStateHolder} do not affect the world until this method is called again. + * + *

The return value of this method indicates whether the change was probably + * successful. It may not be successful if, for example, the location is out + * of the bounds of the extent. It may be unsuccessful if the block passed + * is the same as the one in the world. However, the return value is only an + * estimation and it may be incorrect, but it could be used to count, for + * example, the approximate number of changes.

+ * + * @param position position of the block + * @param block block to set + * @return true if the block was successfully set (return value may not be accurate) + * @throws WorldEditException thrown on an error + */ + > boolean setBlock(BlockVector3 position, T block) throws WorldEditException; + + /** + * Check if this extent fully supports 3D biomes. + * + *

+ * If {@code false}, the extent only visually reads biomes from {@code y = 0}. + * The biomes will still be set in 3D, but the client will only see the one at + * {@code y = 0}. It is up to the caller to determine if they want to set that + * biome instead, or simply warn the actor. + *

+ * + * @return if the extent fully supports 3D biomes + */ + default boolean fullySupports3DBiomes() { + return true; + } + + /** + * Set the biome. + * + * @param position the (x, z) location to set the biome at + * @param biome the biome to set to + * @return true if the biome was successfully set (return value may not be accurate) + * @deprecated Biomes in Minecraft are 3D now, use {@link OutputExtent#setBiome(BlockVector3, BiomeType)} + */ + @Deprecated + default boolean setBiome(BlockVector2 position, BiomeType biome) { + return setBiome(position.toBlockVector3(), biome); + } + + /** + * Set the biome. + * + *

+ * As implementation varies per Minecraft version, this may set more than + * this position's biome. On versions prior to 1.15, this will set the entire + * column. On later versions it will set the 4x4x4 cube. + *

+ * + * @param position the (x, y, z) location to set the biome at + * @param biome the biome to set to + * @return true if the biome was successfully set (return value may not be accurate) + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "setBiome", + delegateParams = { BlockVector3.class, BiomeType.class } + ) + default boolean setBiome(BlockVector3 position, BiomeType biome) { + DeprecationUtil.checkDelegatingOverride(getClass()); + + return setBiome(position.toBlockVector2(), biome); + } + + /** + * Return an {@link Operation} that should be called to tie up loose ends + * (such as to commit changes in a buffer). + * + * @return an operation or null if there is none to execute + */ + @Nullable Operation commit(); + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/TracingExtent.java b/src/main/java/com/sk89q/worldedit/extent/TracingExtent.java new file mode 100644 index 0000000..fc7a129 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/TracingExtent.java @@ -0,0 +1,113 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent; + +import com.google.common.collect.Multimaps; +import com.google.common.collect.SetMultimap; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.collection.BlockMap; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.Set; +import javax.annotation.Nullable; + +/** + * An extent that can report back if an operation fails due to the extent(s) below it. + * + * Internal use only. + */ +public class TracingExtent extends AbstractDelegateExtent { + + public enum Action { + SET_BLOCK, + SET_BIOME, + CREATE_ENTITY, + } + + private final Set touchedLocations = Collections.newSetFromMap(BlockMap.create()); + private final SetMultimap failedActions = Multimaps.newSetMultimap( + BlockMap.create(), () -> EnumSet.noneOf(Action.class) + ); + + /** + * Create a new instance. + * + * @param extent the extent + */ + public TracingExtent(Extent extent) { + super(extent); + } + + public boolean isActive() { + return !touchedLocations.isEmpty(); + } + + public Set getTouchedLocations() { + return Collections.unmodifiableSet(touchedLocations); + } + + public SetMultimap getFailedActions() { + return Multimaps.unmodifiableSetMultimap(failedActions); + } + + @Override + public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { + touchedLocations.add(location); + boolean result = super.setBlock(location, block); + if (!result) { + failedActions.put(location, Action.SET_BLOCK); + } + return result; + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + touchedLocations.add(position); + boolean result = super.setBiome(position, biome); + if (!result) { + failedActions.put(position, Action.SET_BIOME); + } + return result; + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + BlockVector3 blockVector3 = location.toVector().toBlockPoint(); + touchedLocations.add(blockVector3); + Entity result = super.createEntity(location, entity); + if (result == null) { + failedActions.put(blockVector3, Action.CREATE_ENTITY); + } + return result; + } + + @Override + public String toString() { + return "TracingExtent{delegate=" + getExtent() + "}"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java b/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java new file mode 100644 index 0000000..8efd861 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java @@ -0,0 +1,84 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.buffer; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractBufferingExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.collection.BlockMap; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Buffers changes to an {@link Extent} and allows retrieval of the changed blocks, + * without modifying the underlying extent. + */ +public class ExtentBuffer extends AbstractBufferingExtent { + + private final Map buffer = BlockMap.create(); + private final Mask mask; + + /** + * Create a new extent buffer that will buffer every change. + * + * @param delegate the delegate extent for {@link Extent#getBlock(BlockVector3)}, etc. calls + */ + public ExtentBuffer(Extent delegate) { + this(delegate, Masks.alwaysTrue()); + } + + /** + * Create a new extent buffer that will buffer changes that meet the criteria + * of the given mask. + * + * @param delegate the delegate extent for {@link Extent#getBlock(BlockVector3)}, etc. calls + * @param mask the mask + */ + public ExtentBuffer(Extent delegate, Mask mask) { + super(delegate); + checkNotNull(delegate); + checkNotNull(mask); + this.mask = mask; + } + + @Override + protected BaseBlock getBufferedFullBlock(BlockVector3 position) { + if (mask.test(position)) { + return buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos))); + } + return null; + } + + @Override + public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { + if (mask.test(location)) { + buffer.put(location, block.toBaseBlock()); + return true; + } + return false; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java b/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java new file mode 100644 index 0000000..b51d9e6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java @@ -0,0 +1,190 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.buffer; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.pattern.BiomePattern; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.AbstractFlatRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Buffers changes to an {@link Extent} and allows later retrieval for + * actual application of the changes. + * + *

This buffer will not attempt to return results from the buffer when + * accessor methods (such as {@link #getBlock(BlockVector3)}) are called.

+ */ +public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pattern, BiomePattern { + + private final Map buffer = new LinkedHashMap<>(); + private final Map biomeBuffer = new LinkedHashMap<>(); + private final Mask mask; + private BlockVector3 min = null; + private BlockVector3 max = null; + + /** + * Create a new extent buffer that will buffer every change. + * + * @param delegate the delegate extent for {@link Extent#getBlock(BlockVector3)}, etc. calls + */ + public ForgetfulExtentBuffer(Extent delegate) { + this(delegate, Masks.alwaysTrue()); + } + + /** + * Create a new extent buffer that will buffer changes that meet the criteria + * of the given mask. + * + * @param delegate the delegate extent for {@link Extent#getBlock(BlockVector3)}, etc. calls + * @param mask the mask + */ + public ForgetfulExtentBuffer(Extent delegate, Mask mask) { + super(delegate); + checkNotNull(mask); + this.mask = mask; + } + + private void updateBounds(BlockVector3 position) { + // Update minimum + if (min == null) { + min = position; + } else { + min = min.getMinimum(position); + } + + // Update maximum + if (max == null) { + max = position; + } else { + max = max.getMaximum(position); + } + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + updateBounds(location); + + if (mask.test(location)) { + buffer.put(location, block.toBaseBlock()); + return true; + } else { + return getExtent().setBlock(location, block); + } + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + updateBounds(position); + + if (mask.test(position)) { + biomeBuffer.put(position, biome); + return true; + } else { + return getExtent().setBiome(position, biome); + } + } + + @Override + public BaseBlock applyBlock(BlockVector3 pos) { + BaseBlock block = buffer.get(pos); + if (block != null) { + return block; + } else { + return BlockTypes.AIR.getDefaultState().toBaseBlock(); + } + } + + @Override + public BiomeType applyBiome(BlockVector3 pos) { + BiomeType biome = biomeBuffer.get(pos); + if (biome != null) { + return biome; + } else { + return BiomeTypes.OCEAN; + } + } + + /** + * Return a region representation of this buffer. + * + * @return a region + */ + public Region asRegion() { + return new AbstractFlatRegion(null) { + @Override + public BlockVector3 getMinimumPoint() { + return min != null ? min : BlockVector3.ZERO; + } + + @Override + public BlockVector3 getMaximumPoint() { + return max != null ? max : BlockVector3.ZERO; + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + throw new UnsupportedOperationException("Cannot change the size of this region"); + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + throw new UnsupportedOperationException("Cannot change the size of this region"); + } + + @Override + public boolean contains(BlockVector3 position) { + return buffer.containsKey(position); + } + + @Override + public Iterator iterator() { + return buffer.keySet().iterator(); + } + + @Override + public Iterable asFlatRegion() { + return biomeBuffer.keySet() + .stream() + .map(BlockVector3::toBlockVector2) + .collect(Collectors.toSet()); + } + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/cache/LastAccessExtentCache.java b/src/main/java/com/sk89q/worldedit/extent/cache/LastAccessExtentCache.java new file mode 100644 index 0000000..9a5a6d8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/cache/LastAccessExtentCache.java @@ -0,0 +1,97 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.cache; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +/** + * Returns the same cached {@link BlockState} for repeated calls to + * {@link #getBlock(BlockVector3)} with the same position. + */ +public class LastAccessExtentCache extends AbstractDelegateExtent { + + private CachedBlock lastBlock; + private CachedBlock lastFullBlock; + + /** + * Create a new instance. + * + * @param extent the extent + */ + public LastAccessExtentCache(Extent extent) { + super(extent); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + CachedBlock lastBlock = this.lastBlock; + if (lastBlock != null && lastBlock.position.equals(position)) { + return lastBlock.block; + } else { + BlockState block = super.getBlock(position); + this.lastBlock = new CachedBlock<>(position, block); + return block; + } + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + CachedBlock lastFullBlock = this.lastFullBlock; + if (lastFullBlock != null && lastFullBlock.position.equals(position)) { + return lastFullBlock.block; + } else { + BaseBlock block = super.getFullBlock(position); + this.lastFullBlock = new CachedBlock<>(position, block); + return block; + } + } + + @Override + public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { + if (super.setBlock(location, block)) { + if (lastFullBlock != null && lastFullBlock.position.equals(location)) { + this.lastFullBlock = new CachedBlock<>(location, block.toBaseBlock()); + } + if (lastBlock != null && lastBlock.position.equals(location)) { + this.lastBlock = new CachedBlock<>(location, block.toImmutableState()); + } + + return true; + } + return false; + } + + private static class CachedBlock> { + private final BlockVector3 position; + private final B block; + + private CachedBlock(BlockVector3 position, B block) { + this.position = position; + this.block = block; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java new file mode 100644 index 0000000..8cfb4a3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -0,0 +1,220 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Stores block data as a multi-dimensional array of {@link BaseBlock}s and + * other data as lists or maps. + */ +public class BlockArrayClipboard implements Clipboard { + + private final Region region; + private BlockVector3 origin; + private final BaseBlock[][][] blocks; + private BiomeType[][][] biomes = null; + private final List entities = new ArrayList<>(); + + /** + * Create a new instance. + * + *

The origin will be placed at the region's lowest minimum point.

+ * + * @param region the bounding region + */ + public BlockArrayClipboard(Region region) { + checkNotNull(region); + this.region = region.clone(); + this.origin = region.getMinimumPoint(); + + BlockVector3 dimensions = getDimensions(); + blocks = new BaseBlock[dimensions.getBlockX()][dimensions.getBlockY()][dimensions.getBlockZ()]; + } + + @Override + public Region getRegion() { + return region.clone(); + } + + @Override + public BlockVector3 getOrigin() { + return origin; + } + + @Override + public void setOrigin(BlockVector3 origin) { + this.origin = origin; + } + + @Override + public BlockVector3 getDimensions() { + return region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); + } + + @Override + public BlockVector3 getMinimumPoint() { + return region.getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return region.getMaximumPoint(); + } + + @Override + public List getEntities(Region region) { + List filtered = new ArrayList<>(); + for (Entity entity : entities) { + if (region.contains(entity.getLocation().toVector().toBlockPoint())) { + filtered.add(entity); + } + } + return Collections.unmodifiableList(filtered); + } + + @Override + public List getEntities() { + return Collections.unmodifiableList(entities); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + ClipboardEntity ret = new ClipboardEntity(location, entity); + entities.add(ret); + return ret; + } + + @Override + public BlockState getBlock(BlockVector3 position) { + if (region.contains(position)) { + BlockVector3 v = position.subtract(region.getMinimumPoint()); + BaseBlock block = blocks[v.getBlockX()][v.getBlockY()][v.getBlockZ()]; + if (block != null) { + return block.toImmutableState(); + } + } + + return BlockTypes.AIR.getDefaultState(); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + if (region.contains(position)) { + BlockVector3 v = position.subtract(region.getMinimumPoint()); + BaseBlock block = blocks[v.getBlockX()][v.getBlockY()][v.getBlockZ()]; + if (block != null) { + return block; + } + } + + return BlockTypes.AIR.getDefaultState().toBaseBlock(); + } + + @Override + public > boolean setBlock(BlockVector3 position, B block) throws WorldEditException { + if (region.contains(position)) { + BlockVector3 v = position.subtract(region.getMinimumPoint()); + blocks[v.getBlockX()][v.getBlockY()][v.getBlockZ()] = block.toBaseBlock(); + return true; + } else { + return false; + } + } + + @Override + public boolean hasBiomes() { + return biomes != null; + } + + @Override + public BiomeType getBiome(BlockVector3 position) { + if (biomes != null + && position.containedWithin(getMinimumPoint(), getMaximumPoint())) { + BlockVector3 v = position.subtract(region.getMinimumPoint()); + BiomeType biomeType = biomes[v.getBlockX()][v.getBlockY()][v.getBlockZ()]; + if (biomeType != null) { + return biomeType; + } + } + + return BiomeTypes.OCEAN; + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + if (position.containedWithin(getMinimumPoint(), getMaximumPoint())) { + BlockVector3 v = position.subtract(region.getMinimumPoint()); + if (biomes == null) { + biomes = new BiomeType[region.getWidth()][region.getHeight()][region.getLength()]; + } + biomes[v.getBlockX()][v.getBlockY()][v.getBlockZ()] = biome; + return true; + } + return false; + } + + @Nullable + @Override + public Operation commit() { + return null; + } + + /** + * Stores entity data. + */ + private class ClipboardEntity extends StoredEntity { + ClipboardEntity(Location location, BaseEntity entity) { + super(location, entity); + } + + @Override + public boolean remove() { + return entities.remove(this); + } + + @Nullable + @Override + public T getFacet(Class cls) { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java new file mode 100644 index 0000000..d5d413e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -0,0 +1,71 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; + +/** + * Specifies an object that implements something suitable as a "clipboard." + */ +public interface Clipboard extends Extent { + + /** + * Get the bounding region of this extent. + * + *

Implementations should return a copy of the region.

+ * + * @return the bounding region + */ + Region getRegion(); + + /** + * Get the dimensions of the copy, which is at minimum (1, 1, 1). + * + * @return the dimensions + */ + BlockVector3 getDimensions(); + + /** + * Get the origin point from which the copy was made from. + * + * @return the origin + */ + BlockVector3 getOrigin(); + + /** + * Set the origin point from which the copy was made from. + * + * @param origin the origin + */ + void setOrigin(BlockVector3 origin); + + /** + * Returns true if the clipboard has biome data. This can be checked since {@link Extent#getBiome(BlockVector3)} + * strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes#OCEAN} instead of {@code null} + * if biomes aren't present. + * + * @return true if the clipboard has biome data set + */ + default boolean hasBiomes() { + return false; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/StoredEntity.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/StoredEntity.java new file mode 100644 index 0000000..eac1b75 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/StoredEntity.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard; + +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Location; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An implementation of {@link Entity} that stores a {@link BaseEntity} with it. + * + *

Calls to {@link #getState()} return a clone.

+ */ +abstract class StoredEntity implements Entity { + + private final Location location; + private final BaseEntity entity; + + /** + * Create a new instance. + * + * @param location the location + * @param entity the entity (which will be copied) + */ + StoredEntity(Location location, BaseEntity entity) { + checkNotNull(location); + checkNotNull(entity); + this.location = location; + this.entity = new BaseEntity(entity); + } + + /** + * Get the entity state. This is not a copy. + * + * @return the entity + */ + BaseEntity getEntity() { + return entity; + } + + @Override + public BaseEntity getState() { + return new BaseEntity(entity); + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public boolean setLocation(Location location) { + throw new IllegalArgumentException("StoredEntities are immutable"); + } + + @Override + public Extent getExtent() { + return location.getExtent(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java new file mode 100644 index 0000000..379c5e5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -0,0 +1,147 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.google.common.collect.ImmutableSet; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.jnbt.NamedTag; +import com.sk89q.jnbt.Tag; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Map; +import java.util.Set; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +/** + * A collection of supported clipboard formats. + */ +public enum BuiltInClipboardFormat implements ClipboardFormat { + + /** + * The Schematic format used by MCEdit. + */ + MCEDIT_SCHEMATIC("mcedit", "mce", "schematic") { + + @Override + public String getPrimaryFileExtension() { + return "schematic"; + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream)); + return new MCEditSchematicReader(nbtStream); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + throw new IOException("This format does not support saving"); + } + + @Override + public boolean isFormat(File file) { + try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) { + NamedTag rootTag = str.readNamedTag(); + if (!rootTag.getName().equals("Schematic")) { + return false; + } + CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); + + // Check + Map schematic = schematicTag.getValue(); + if (!schematic.containsKey("Materials")) { + return false; + } + } catch (Exception e) { + return false; + } + return true; + } + }, + SPONGE_SCHEMATIC("sponge", "schem") { + + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream)); + return new SpongeSchematicReader(nbtStream); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + NBTOutputStream nbtStream = new NBTOutputStream(new GZIPOutputStream(outputStream)); + return new SpongeSchematicWriter(nbtStream); + } + + @Override + public boolean isFormat(File file) { + try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) { + NamedTag rootTag = str.readNamedTag(); + if (!rootTag.getName().equals("Schematic")) { + return false; + } + CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); + + // Check + Map schematic = schematicTag.getValue(); + if (!schematic.containsKey("Version")) { + return false; + } + } catch (Exception e) { + return false; + } + + return true; + } + }; + + private final ImmutableSet aliases; + + BuiltInClipboardFormat(String... aliases) { + this.aliases = ImmutableSet.copyOf(aliases); + } + + @Override + public String getName() { + return name(); + } + + @Override + public Set getAliases() { + return this.aliases; + } + + @Override + public Set getFileExtensions() { + return ImmutableSet.of(getPrimaryFileExtension()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java new file mode 100644 index 0000000..1164dbb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java @@ -0,0 +1,87 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Set; + +/** + * A collection of supported clipboard formats. + */ +public interface ClipboardFormat { + + /** + * Returns the name of this format. + * + * @return The name of the format + */ + String getName(); + + /** + * Get a set of aliases. + * + * @return a set of aliases + */ + Set getAliases(); + + /** + * Create a reader. + * + * @param inputStream the input stream + * @return a reader + * @throws IOException thrown on I/O error + */ + ClipboardReader getReader(InputStream inputStream) throws IOException; + + /** + * Create a writer. + * + * @param outputStream the output stream + * @return a writer + * @throws IOException thrown on I/O error + */ + ClipboardWriter getWriter(OutputStream outputStream) throws IOException; + + /** + * Return whether the given file is of this format. + * + * @param file the file + * @return true if the given file is of this format + */ + boolean isFormat(File file); + + /** + * Get the file extension this format primarily uses. + * + * @return The primary file extension + */ + String getPrimaryFileExtension(); + + /** + * Get the file extensions this format is commonly known to use. This should + * include {@link #getPrimaryFileExtension()}. + * + * @return The file extensions this format might be known by + */ + Set getFileExtensions(); +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java new file mode 100644 index 0000000..b4e0fd6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -0,0 +1,126 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.sk89q.worldedit.WorldEdit; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ClipboardFormats { + + private static final Map aliasMap = new HashMap<>(); + private static final Multimap fileExtensionMap = HashMultimap.create(); + private static final List registeredFormats = new ArrayList<>(); + + public static void registerClipboardFormat(ClipboardFormat format) { + checkNotNull(format); + + for (String key : format.getAliases()) { + String lowKey = key.toLowerCase(Locale.ENGLISH); + ClipboardFormat old = aliasMap.put(lowKey, format); + if (old != null) { + aliasMap.put(lowKey, old); + WorldEdit.logger.warn(format.getClass().getName() + " cannot override existing alias '" + lowKey + "' used by " + old.getClass().getName()); + } + } + for (String ext : format.getFileExtensions()) { + String lowExt = ext.toLowerCase(Locale.ENGLISH); + fileExtensionMap.put(lowExt, format); + } + registeredFormats.add(format); + } + + static { + for (BuiltInClipboardFormat format : BuiltInClipboardFormat.values()) { + registerClipboardFormat(format); + } + } + + /** + * Find the clipboard format named by the given alias. + * + * @param alias + * the alias + * @return the format, otherwise null if none is matched + */ + @Nullable + public static ClipboardFormat findByAlias(String alias) { + checkNotNull(alias); + return aliasMap.get(alias.toLowerCase(Locale.ENGLISH).trim()); + } + + /** + * Detect the format of given a file. + * + * @param file + * the file + * @return the format, otherwise null if one cannot be detected + */ + @Nullable + public static ClipboardFormat findByFile(File file) { + checkNotNull(file); + + for (ClipboardFormat format : registeredFormats) { + if (format.isFormat(file)) { + return format; + } + } + + return null; + } + + /** + * A mapping from extensions to formats. + * + * @return a multimap from a file extension to the potential matching formats. + */ + public static Multimap getFileExtensionMap() { + return Multimaps.unmodifiableMultimap(fileExtensionMap); + } + + public static Collection getAll() { + return Collections.unmodifiableCollection(registeredFormats); + } + + /** + * Not public API, only used by SchematicCommands. + * It is not in SchematicCommands because it may rely on internal register calls. + */ + public static String[] getFileExtensionArray() { + return fileExtensionMap.keySet().toArray(new String[fileExtensionMap.keySet().size()]); + } + + private ClipboardFormats() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java new file mode 100644 index 0000000..a7a3e33 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java @@ -0,0 +1,51 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; + +import java.io.Closeable; +import java.io.IOException; +import java.util.OptionalInt; + +/** + * Reads {@code Clipboard}s. + * + * @see Clipboard + */ +public interface ClipboardReader extends Closeable { + + /** + * Read a {@code Clipboard}. + * + * @return the read clipboard + * @throws IOException thrown on I/O error + */ + Clipboard read() throws IOException; + + /** + * Get the DataVersion from a file (if possible). + * + * @return The data version, or empty + */ + default OptionalInt getDataVersion() { + return OptionalInt.empty(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java new file mode 100644 index 0000000..ea41f0b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; + +import java.io.Closeable; +import java.io.IOException; + +/** + * Writes {@code Clipboard}s. + * + * @see Clipboard + */ +public interface ClipboardWriter extends Closeable { + + /** + * Writes a clipboard. + * + * @param clipboard the clipboard + * @throws IOException thrown on I/O error + */ + void write(Clipboard clipboard) throws IOException; + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java new file mode 100644 index 0000000..f1b0b06 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java @@ -0,0 +1,412 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.google.common.collect.ImmutableList; +import com.sk89q.jnbt.*; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.legacycompat.*; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.collection.BlockMap; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.registry.LegacyMapper; +import com.sk89q.worldedit.world.storage.NBTConversions; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.util.*; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Reads schematic files that are compatible with MCEdit and other editors. + */ +public class MCEditSchematicReader extends NBTSchematicReader { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private final NBTInputStream inputStream; + private final DataFixer fixer; + private static final ImmutableList COMPATIBILITY_HANDLERS + = ImmutableList.of( + new SignCompatibilityHandler(), + new FlowerPotCompatibilityHandler(), + new NoteBlockCompatibilityHandler(), + new SkullBlockCompatibilityHandler(), + new BannerBlockCompatibilityHandler(), + new BedBlockCompatibilityHandler() + ); + private static final ImmutableList ENTITY_COMPATIBILITY_HANDLERS + = ImmutableList.of( + new Pre13HangingCompatibilityHandler() + ); + + /** + * Create a new instance. + * + * @param inputStream the input stream to read from + */ + public MCEditSchematicReader(NBTInputStream inputStream) { + checkNotNull(inputStream); + this.inputStream = inputStream; + this.fixer = null; + //com.sk89q.worldedit.WorldEdit.getInstance().getPlatformManager().queryCapability( + //com.sk89q.worldedit.extension.platform.Capability.WORLD_EDITING).getDataFixer(); + } + + @Override + public Clipboard read() throws IOException { + // Schematic tag + NamedTag rootTag = inputStream.readNamedTag(); + if (!rootTag.getName().equals("Schematic")) { + throw new IOException("Tag 'Schematic' does not exist or is not first"); + } + CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); + + // Check + Map schematic = schematicTag.getValue(); + if (!schematic.containsKey("Blocks")) { + throw new IOException("Schematic file is missing a 'Blocks' tag"); + } + + // Check type of Schematic + String materials = requireTag(schematic, "Materials", StringTag.class).getValue(); + if (!materials.equals("Alpha")) { + throw new IOException("Schematic file is not an Alpha schematic"); + } + + // ==================================================================== + // Metadata + // ==================================================================== + + BlockVector3 origin; + Region region; + + // Get information + short width = requireTag(schematic, "Width", ShortTag.class).getValue(); + short height = requireTag(schematic, "Height", ShortTag.class).getValue(); + short length = requireTag(schematic, "Length", ShortTag.class).getValue(); + + try { + int originX = requireTag(schematic, "WEOriginX", IntTag.class).getValue(); + int originY = requireTag(schematic, "WEOriginY", IntTag.class).getValue(); + int originZ = requireTag(schematic, "WEOriginZ", IntTag.class).getValue(); + BlockVector3 min = BlockVector3.at(originX, originY, originZ); + + int offsetX = requireTag(schematic, "WEOffsetX", IntTag.class).getValue(); + int offsetY = requireTag(schematic, "WEOffsetY", IntTag.class).getValue(); + int offsetZ = requireTag(schematic, "WEOffsetZ", IntTag.class).getValue(); + BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ); + + origin = min.subtract(offset); + region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); + } catch (IOException ignored) { + origin = BlockVector3.ZERO; + region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); + } + + // ==================================================================== + // Blocks + // ==================================================================== + + // Get blocks + byte[] blockId = requireTag(schematic, "Blocks", ByteArrayTag.class).getValue(); + byte[] blockData = requireTag(schematic, "Data", ByteArrayTag.class).getValue(); + byte[] addId = new byte[0]; + short[] blocks = new short[blockId.length]; // Have to later combine IDs + + // We support 4096 block IDs using the same method as vanilla Minecraft, where + // the highest 4 bits are stored in a separate byte array. + if (schematic.containsKey("AddBlocks")) { + addId = requireTag(schematic, "AddBlocks", ByteArrayTag.class).getValue(); + } + + // Combine the AddBlocks data with the first 8-bit block ID + for (int index = 0; index < blockId.length; index++) { + if ((index >> 1) >= addId.length) { // No corresponding AddBlocks index + blocks[index] = (short) (blockId[index] & 0xFF); + } else { + if ((index & 1) == 0) { + blocks[index] = (short) (((addId[index >> 1] & 0x0F) << 8) + (blockId[index] & 0xFF)); + } else { + blocks[index] = (short) (((addId[index >> 1] & 0xF0) << 4) + (blockId[index] & 0xFF)); + } + } + } + + // Need to pull out tile entities + final ListTag tileEntityTag = getTag(schematic, "TileEntities", ListTag.class); + List tileEntities = tileEntityTag == null ? new ArrayList<>() : tileEntityTag.getValue(); + BlockMap tileEntityBlocks = BlockMap.createForBaseBlock(); + + for (Tag tag : tileEntities) { + if (!(tag instanceof CompoundTag)) { + continue; + } + CompoundTag t = (CompoundTag) tag; + Map values = new HashMap<>(t.getValue()); + String id = t.getString("id"); + values.put("id", new StringTag(convertBlockEntityId(id))); + int x = t.getInt("x"); + int y = t.getInt("y"); + int z = t.getInt("z"); + int index = y * width * length + z * width + x; + + BlockState block = getBlockState(blocks[index], blockData[index]); + BlockState newBlock = block; + if (newBlock != null) { + for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { + if (handler.isAffectedBlock(newBlock)) { + newBlock = handler.updateNBT(block, values).toImmutableState(); + if (newBlock == null || values.isEmpty()) { + break; + } + } + } + } + if (values.isEmpty()) { + t = null; + } else { + t = new CompoundTag(values); + } + + if (fixer != null && t != null) { + t = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, t, -1); + } + + BlockVector3 vec = BlockVector3.at(x, y, z); + // Insert into the map if we have changed the block or have a tag + BlockState blockToInsert = newBlock != null + ? newBlock + : (t != null ? block : null); + if (blockToInsert != null) { + BaseBlock baseBlock = t != null + ? blockToInsert.toBaseBlock(new CompoundTag(t.getValue())) + : blockToInsert.toBaseBlock(); + tileEntityBlocks.put(vec, baseBlock); + } + } + + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOrigin(origin); + + + Set unknownBlocks = new HashSet<>(); + for (int x = 0; x < width; ++x) { + for (int y = 0; y < height; ++y) { + for (int z = 0; z < length; ++z) { + int index = y * width * length + z * width + x; + BlockVector3 pt = BlockVector3.at(x, y, z); + BaseBlock state = Optional.ofNullable(tileEntityBlocks.get(pt)) + .orElseGet(() -> { + BlockState blockState = getBlockState(blocks[index], blockData[index]); + return blockState == null ? null : blockState.toBaseBlock(); + }); + + try { + if (state != null) { + clipboard.setBlock(region.getMinimumPoint().add(pt), state); + } else { + short block = blocks[index]; + byte data = blockData[index]; + int combined = block << 8 | data; + if (unknownBlocks.add(combined)) { + LOGGER.warn("Unknown block when loading schematic: " + + block + ":" + data + ". This is most likely a bad schematic."); + } + } + } catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this + } + } + } + } + + // ==================================================================== + // Entities + // ==================================================================== + + ListTag entityList = getTag(schematic, "Entities", ListTag.class); + if (entityList != null) { + List entityTags = entityList.getValue(); + for (Tag tag : entityTags) { + if (tag instanceof CompoundTag) { + CompoundTag compound = (CompoundTag) tag; + if (fixer != null) { + compound = fixer.fixUp(DataFixer.FixTypes.ENTITY, compound, -1); + } + String id = convertEntityId(compound.getString("id")); + Location location = NBTConversions.toLocation(clipboard, compound.getListTag("Pos"), compound.getListTag("Rotation")); + if (!id.isEmpty()) { + EntityType entityType = EntityTypes.get(id.toLowerCase(Locale.ROOT)); + if (entityType != null) { + for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) { + if (compatibilityHandler.isAffectedEntity(entityType, compound)) { + compound = compatibilityHandler.updateNBT(entityType, compound); + } + } + BaseEntity state = new BaseEntity(entityType, compound); + clipboard.createEntity(location, state); + } else { + LOGGER.warn("Unknown entity when pasting schematic: " + id.toLowerCase(Locale.ROOT)); + } + } + } + } + } + + return clipboard; + } + + private String convertEntityId(String id) { + switch (id) { + case "AreaEffectCloud": return "area_effect_cloud"; + case "ArmorStand": return "armor_stand"; + case "CaveSpider": return "cave_spider"; + case "MinecartChest": return "chest_minecart"; + case "DragonFireball": return "dragon_fireball"; + case "ThrownEgg": return "egg"; + case "EnderDragon": return "ender_dragon"; + case "ThrownEnderpearl": return "ender_pearl"; + case "FallingSand": return "falling_block"; + case "FireworksRocketEntity": return "fireworks_rocket"; + case "MinecartFurnace": return "furnace_minecart"; + case "MinecartHopper": return "hopper_minecart"; + case "EntityHorse": return "horse"; + case "ItemFrame": return "item_frame"; + case "LeashKnot": return "leash_knot"; + case "LightningBolt": return "lightning_bolt"; + case "LavaSlime": return "magma_cube"; + case "MinecartRideable": return "minecart"; + case "MushroomCow": return "mooshroom"; + case "Ozelot": return "ocelot"; + case "PolarBear": return "polar_bear"; + case "ThrownPotion": return "potion"; + case "ShulkerBullet": return "shulker_bullet"; + case "SmallFireball": return "small_fireball"; + case "MinecartSpawner": return "spawner_minecart"; + case "SpectralArrow": return "spectral_arrow"; + case "PrimedTnt": return "tnt"; + case "MinecartTNT": return "tnt_minecart"; + case "VillagerGolem": return "villager_golem"; + case "WitherBoss": return "wither"; + case "WitherSkull": return "wither_skull"; + case "PigZombie": return "zombie_pigman"; + case "XPOrb": + case "xp_orb": + return "experience_orb"; + case "ThrownExpBottle": + case "xp_bottle": + return "experience_bottle"; + case "EyeOfEnderSignal": + case "eye_of_ender_signal": + return "eye_of_ender"; + case "EnderCrystal": + case "ender_crystal": + return "end_crystal"; + case "fireworks_rocket": return "firework_rocket"; + case "MinecartCommandBlock": + case "commandblock_minecart": + return "command_block_minecart"; + case "snowman": return "snow_golem"; + case "villager_golem": return "iron_golem"; + case "evocation_fangs": return "evoker_fangs"; + case "evocation_illager": return "evoker"; + case "vindication_illager": return "vindicator"; + case "illusion_illager": return "illusioner"; + default: return id; + } + } + + private String convertBlockEntityId(String id) { + switch (id) { + case "Cauldron": + return "brewing_stand"; + case "Control": + return "command_block"; + case "DLDetector": + return "daylight_detector"; + case "Trap": + return "dispenser"; + case "EnchantTable": + return "enchanting_table"; + case "EndGateway": + return "end_gateway"; + case "AirPortal": + return "end_portal"; + case "EnderChest": + return "ender_chest"; + case "FlowerPot": + return "flower_pot"; + case "RecordPlayer": + return "jukebox"; + case "MobSpawner": + return "mob_spawner"; + case "Music": + case "noteblock": + return "note_block"; + case "Structure": + return "structure_block"; + case "Chest": + return "chest"; + case "Sign": + return "sign"; + case "Banner": + return "banner"; + case "Beacon": + return "beacon"; + case "Comparator": + return "comparator"; + case "Dropper": + return "dropper"; + case "Furnace": + return "furnace"; + case "Hopper": + return "hopper"; + case "Skull": + return "skull"; + default: + return id; + } + } + + private BlockState getBlockState(int id, int data) { + BlockState foundBlock = LegacyMapper.getInstance().getBlockFromLegacy(id, data); + if (foundBlock == null && data != 0) { + // Some schematics contain invalid data values, so try without the data value + return LegacyMapper.getInstance().getBlockFromLegacy(id, 0); + } + return foundBlock; + } + + @Override + public void close() throws IOException { + inputStream.close(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java new file mode 100644 index 0000000..a3d841d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.sk89q.jnbt.Tag; + +import java.io.IOException; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * Base class for NBT schematic readers. + */ +public abstract class NBTSchematicReader implements ClipboardReader { + + protected static T requireTag(Map items, String key, Class expected) throws IOException { + if (!items.containsKey(key)) { + throw new IOException("Schematic file is missing a \"" + key + "\" tag of type " + + expected.getName()); + } + + Tag tag = items.get(key); + if (!expected.isInstance(tag)) { + throw new IOException(key + " tag is not of tag type " + expected.getName() + ", got " + + tag.getClass().getName() + " instead"); + } + + return expected.cast(tag); + } + + @Nullable + protected static T getTag(Map items, String key, Class expected) { + if (!items.containsKey(key)) { + return null; + } + + Tag test = items.get(key); + if (!expected.isInstance(test)) { + return null; + } + + return expected.cast(test); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java new file mode 100644 index 0000000..3562022 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java @@ -0,0 +1,399 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.google.common.collect.Maps; +import com.sk89q.jnbt.*; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.storage.NBTConversions; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.OptionalInt; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Reads schematic files using the Sponge Schematic Specification. + */ +public class SpongeSchematicReader extends NBTSchematicReader { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private final NBTInputStream inputStream; + private DataFixer fixer = null; + private int schematicVersion = -1; + private int dataVersion = -1; + + /** + * Create a new instance. + * + * @param inputStream the input stream to read from + */ + public SpongeSchematicReader(NBTInputStream inputStream) { + checkNotNull(inputStream); + this.inputStream = inputStream; + } + + @Override + public Clipboard read() throws IOException { + CompoundTag schematicTag = getBaseTag(); + Map schematic = schematicTag.getValue(); + + final Platform platform = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.WORLD_EDITING); + int liveDataVersion = platform.getDataVersion(); + + if (schematicVersion == 1) { + dataVersion = Constants.DATA_VERSION_MC_1_13_2; // this is a relatively safe assumption unless someone imports a schematic from 1.12, e.g. sponge 7.1- + fixer = platform.getDataFixer(); + return readVersion1(schematicTag); + } else if (schematicVersion == 2) { + dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); + if (dataVersion < 0) { + LOGGER.warn("Schematic has an unknown data version ({}). Data may be incompatible.", + dataVersion); + // Do not DFU unknown data + dataVersion = liveDataVersion; + } + if (dataVersion > liveDataVersion) { + LOGGER.warn("Schematic was made in a newer Minecraft version ({} > {}). Data may be incompatible.", + dataVersion, liveDataVersion); + } else if (dataVersion < liveDataVersion) { + fixer = platform.getDataFixer(); + if (fixer != null) { + LOGGER.debug("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.", + dataVersion, liveDataVersion); + } else { + LOGGER.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.", + dataVersion, liveDataVersion); + } + } + + BlockArrayClipboard clip = readVersion1(schematicTag); + return readVersion2(clip, schematicTag); + } + throw new IOException("This schematic version is currently not supported"); + } + + @Override + public OptionalInt getDataVersion() { + try { + CompoundTag schematicTag = getBaseTag(); + Map schematic = schematicTag.getValue(); + if (schematicVersion == 1) { + return OptionalInt.of(Constants.DATA_VERSION_MC_1_13_2); + } else if (schematicVersion == 2) { + int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); + if (dataVersion < 0) { + return OptionalInt.empty(); + } + return OptionalInt.of(dataVersion); + } + return OptionalInt.empty(); + } catch (IOException e) { + return OptionalInt.empty(); + } + } + + private CompoundTag getBaseTag() throws IOException { + NamedTag rootTag = inputStream.readNamedTag(); + CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); + + // Check + Map schematic = schematicTag.getValue(); + + schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue(); + return schematicTag; + } + + private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOException { + BlockVector3 origin; + Region region; + Map schematic = schematicTag.getValue(); + + int width = requireTag(schematic, "Width", ShortTag.class).getValue(); + int height = requireTag(schematic, "Height", ShortTag.class).getValue(); + int length = requireTag(schematic, "Length", ShortTag.class).getValue(); + + IntArrayTag offsetTag = getTag(schematic, "Offset", IntArrayTag.class); + int[] offsetParts; + if (offsetTag != null) { + offsetParts = offsetTag.getValue(); + if (offsetParts.length != 3) { + throw new IOException("Invalid offset specified in schematic."); + } + } else { + offsetParts = new int[] {0, 0, 0}; + } + + BlockVector3 min = BlockVector3.at(offsetParts[0], offsetParts[1], offsetParts[2]); + + CompoundTag metadataTag = getTag(schematic, "Metadata", CompoundTag.class); + if (metadataTag != null && metadataTag.containsKey("WEOffsetX")) { + // We appear to have WorldEdit Metadata + Map metadata = metadataTag.getValue(); + int offsetX = requireTag(metadata, "WEOffsetX", IntTag.class).getValue(); + int offsetY = requireTag(metadata, "WEOffsetY", IntTag.class).getValue(); + int offsetZ = requireTag(metadata, "WEOffsetZ", IntTag.class).getValue(); + BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ); + origin = min.subtract(offset); + region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); + } else { + origin = min; + region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); + } + + IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class); + Map paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); + if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) { + throw new IOException("Block palette size does not match expected size."); + } + + Map palette = new HashMap<>(); + + ParserContext parserContext = new ParserContext(); + parserContext.setRestricted(false); + parserContext.setTryLegacy(false); + parserContext.setPreferringWildcard(false); + + for (String palettePart : paletteObject.keySet()) { + int id = requireTag(paletteObject, palettePart, IntTag.class).getValue(); + if (fixer != null) { + palettePart = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart, dataVersion); + } + BlockState state; + try { + state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState(); + } catch (InputParseException e) { + LOGGER.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air."); + state = BlockTypes.AIR.getDefaultState(); + } + palette.put(id, state); + } + + byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue(); + + Map> tileEntitiesMap = new HashMap<>(); + ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class); + if (tileEntities == null) { + tileEntities = getTag(schematic, "TileEntities", ListTag.class); + } + if (tileEntities != null) { + List> tileEntityTags = tileEntities.getValue().stream() + .map(tag -> (CompoundTag) tag) + .map(CompoundTag::getValue) + .collect(Collectors.toList()); + + for (Map tileEntity : tileEntityTags) { + int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue(); + final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]); + Map values = Maps.newHashMap(tileEntity); + values.put("x", new IntTag(pt.getBlockX())); + values.put("y", new IntTag(pt.getBlockY())); + values.put("z", new IntTag(pt.getBlockZ())); + values.put("id", values.get("Id")); + values.remove("Id"); + values.remove("Pos"); + if (fixer != null) { + tileEntity = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values), dataVersion).getValue(); + } else { + tileEntity = values; + } + tileEntitiesMap.put(pt, tileEntity); + } + } + + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOrigin(origin); + + int index = 0; + int i = 0; + int value; + int varintLength; + while (i < blocks.length) { + value = 0; + varintLength = 0; + + while (true) { + value |= (blocks[i] & 127) << (varintLength++ * 7); + if (varintLength > 5) { + throw new IOException("VarInt too big (probably corrupted data)"); + } + if ((blocks[i] & 128) != 128) { + i++; + break; + } + i++; + } + // index = (y * length * width) + (z * width) + x + int y = index / (width * length); + int z = (index % (width * length)) / width; + int x = (index % (width * length)) % width; + BlockState state = palette.get(value); + BlockVector3 pt = BlockVector3.at(x, y, z); + try { + if (tileEntitiesMap.containsKey(pt)) { + clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state.toBaseBlock(new CompoundTag(tileEntitiesMap.get(pt)))); + } else { + clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state); + } + } catch (WorldEditException e) { + throw new IOException("Failed to load a block in the schematic"); + } + + index++; + } + + return clipboard; + } + + private Clipboard readVersion2(BlockArrayClipboard version1, CompoundTag schematicTag) throws IOException { + Map schematic = schematicTag.getValue(); + if (schematic.containsKey("BiomeData")) { + readBiomes(version1, schematic); + } + if (schematic.containsKey("Entities")) { + readEntities(version1, schematic); + } + return version1; + } + + private void readBiomes(BlockArrayClipboard clipboard, Map schematic) throws IOException { + ByteArrayTag dataTag = requireTag(schematic, "BiomeData", ByteArrayTag.class); + IntTag maxTag = requireTag(schematic, "BiomePaletteMax", IntTag.class); + CompoundTag paletteTag = requireTag(schematic, "BiomePalette", CompoundTag.class); + + Map palette = new HashMap<>(); + if (maxTag.getValue() != paletteTag.getValue().size()) { + throw new IOException("Biome palette size does not match expected size."); + } + + for (Entry palettePart : paletteTag.getValue().entrySet()) { + String key = palettePart.getKey(); + if (fixer != null) { + key = fixer.fixUp(DataFixer.FixTypes.BIOME, key, dataVersion); + } + BiomeType biome = BiomeTypes.get(key); + if (biome == null) { + LOGGER.warn("Unknown biome type :" + key + + " in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?"); + } + Tag idTag = palettePart.getValue(); + if (!(idTag instanceof IntTag)) { + throw new IOException("Biome mapped to non-Int tag."); + } + palette.put(((IntTag) idTag).getValue(), biome); + } + + int width = clipboard.getDimensions().getX(); + + byte[] biomes = dataTag.getValue(); + int biomeIndex = 0; + int biomeJ = 0; + int bVal; + int varIntLength; + BlockVector3 min = clipboard.getMinimumPoint(); + while (biomeJ < biomes.length) { + bVal = 0; + varIntLength = 0; + + while (true) { + bVal |= (biomes[biomeJ] & 127) << (varIntLength++ * 7); + if (varIntLength > 5) { + throw new IOException("VarInt too big (probably corrupted data)"); + } + if (((biomes[biomeJ] & 128) != 128)) { + biomeJ++; + break; + } + biomeJ++; + } + int z = biomeIndex / width; + int x = biomeIndex % width; + BiomeType type = palette.get(bVal); + for (int y = 0; y < clipboard.getRegion().getHeight(); y++) { + clipboard.setBiome(min.add(x, y, z), type); + } + biomeIndex++; + } + } + + private void readEntities(BlockArrayClipboard clipboard, Map schematic) throws IOException { + List entList = requireTag(schematic, "Entities", ListTag.class).getValue(); + if (entList.isEmpty()) { + return; + } + for (Tag et : entList) { + if (!(et instanceof CompoundTag)) { + continue; + } + CompoundTag entityTag = (CompoundTag) et; + Map tags = entityTag.getValue(); + String id = requireTag(tags, "Id", StringTag.class).getValue(); + entityTag = entityTag.createBuilder().putString("id", id).remove("Id").build(); + + if (fixer != null) { + entityTag = fixer.fixUp(DataFixer.FixTypes.ENTITY, entityTag, dataVersion); + } + + EntityType entityType = EntityTypes.get(id); + if (entityType != null) { + Location location = NBTConversions.toLocation(clipboard, + requireTag(tags, "Pos", ListTag.class), + requireTag(tags, "Rotation", ListTag.class)); + BaseEntity state = new BaseEntity(entityType, entityTag); + clipboard.createEntity(location, state); + } else { + LOGGER.warn("Unknown entity when pasting schematic: " + id); + } + } + } + + @Override + public void close() throws IOException { + inputStream.close(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java new file mode 100644 index 0000000..8a86c10 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java @@ -0,0 +1,289 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.google.common.collect.Maps; +import com.sk89q.jnbt.ByteArrayTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.DoubleTag; +import com.sk89q.jnbt.FloatTag; +import com.sk89q.jnbt.IntArrayTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Writes schematic files using the Sponge schematic format. + */ +public class SpongeSchematicWriter implements ClipboardWriter { + + private static final int CURRENT_VERSION = 2; + + private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; + private final NBTOutputStream outputStream; + + /** + * Create a new schematic writer. + * + * @param outputStream the output stream to write to + */ + public SpongeSchematicWriter(NBTOutputStream outputStream) { + checkNotNull(outputStream); + this.outputStream = outputStream; + } + + @Override + public void write(Clipboard clipboard) throws IOException { + // For now always write the latest version. Maybe provide support for earlier if more appear. + outputStream.writeNamedTag("Schematic", new CompoundTag(write2(clipboard))); + } + + /** + * Writes a version 2 schematic file. + * + * @param clipboard The clipboard + * @return The schematic map + */ + private Map write2(Clipboard clipboard) { + Region region = clipboard.getRegion(); + BlockVector3 origin = clipboard.getOrigin(); + BlockVector3 min = region.getMinimumPoint(); + BlockVector3 offset = min.subtract(origin); + int width = region.getWidth(); + int height = region.getHeight(); + int length = region.getLength(); + + if (width > MAX_SIZE) { + throw new IllegalArgumentException("Width of region too large for a .schematic"); + } + if (height > MAX_SIZE) { + throw new IllegalArgumentException("Height of region too large for a .schematic"); + } + if (length > MAX_SIZE) { + throw new IllegalArgumentException("Length of region too large for a .schematic"); + } + + Map schematic = new HashMap<>(); + schematic.put("Version", new IntTag(CURRENT_VERSION)); + schematic.put("DataVersion", new IntTag( + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion())); + + Map metadata = new HashMap<>(); + metadata.put("WEOffsetX", new IntTag(offset.getBlockX())); + metadata.put("WEOffsetY", new IntTag(offset.getBlockY())); + metadata.put("WEOffsetZ", new IntTag(offset.getBlockZ())); + + schematic.put("Metadata", new CompoundTag(metadata)); + + schematic.put("Width", new ShortTag((short) width)); + schematic.put("Height", new ShortTag((short) height)); + schematic.put("Length", new ShortTag((short) length)); + + // The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin' + schematic.put("Offset", new IntArrayTag(new int[]{ + min.getBlockX(), + min.getBlockY(), + min.getBlockZ(), + })); + + int paletteMax = 0; + Map palette = new HashMap<>(); + + List tileEntities = new ArrayList<>(); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length); + + for (int y = 0; y < height; y++) { + int y0 = min.getBlockY() + y; + for (int z = 0; z < length; z++) { + int z0 = min.getBlockZ() + z; + for (int x = 0; x < width; x++) { + int x0 = min.getBlockX() + x; + BlockVector3 point = BlockVector3.at(x0, y0, z0); + BaseBlock block = clipboard.getFullBlock(point); + if (block.getNbtData() != null) { + Map values = new HashMap<>(block.getNbtData().getValue()); + + values.remove("id"); // Remove 'id' if it exists. We want 'Id' + + // Positions are kept in NBT, we don't want that. + values.remove("x"); + values.remove("y"); + values.remove("z"); + + values.put("Id", new StringTag(block.getNbtId())); + values.put("Pos", new IntArrayTag(new int[] { x, y, z })); + + tileEntities.add(new CompoundTag(values)); + } + + String blockKey = block.toImmutableState().getAsString(); + int blockId; + if (palette.containsKey(blockKey)) { + blockId = palette.get(blockKey); + } else { + blockId = paletteMax; + palette.put(blockKey, blockId); + paletteMax++; + } + + while ((blockId & -128) != 0) { + buffer.write(blockId & 127 | 128); + blockId >>>= 7; + } + buffer.write(blockId); + } + } + } + + schematic.put("PaletteMax", new IntTag(paletteMax)); + + Map paletteTag = new HashMap<>(); + palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value))); + + schematic.put("Palette", new CompoundTag(paletteTag)); + schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray())); + schematic.put("BlockEntities", new ListTag(CompoundTag.class, tileEntities)); + + // version 2 stuff + if (clipboard.hasBiomes()) { + writeBiomes(clipboard, schematic); + } + + if (!clipboard.getEntities().isEmpty()) { + writeEntities(clipboard, schematic); + } + + return schematic; + } + + private void writeBiomes(Clipboard clipboard, Map schematic) { + BlockVector3 min = clipboard.getMinimumPoint(); + int width = clipboard.getRegion().getWidth(); + int length = clipboard.getRegion().getLength(); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * length); + + int paletteMax = 0; + Map palette = new HashMap<>(); + + for (int z = 0; z < length; z++) { + int z0 = min.getBlockZ() + z; + for (int x = 0; x < width; x++) { + int x0 = min.getBlockX() + x; + BlockVector3 pt = BlockVector3.at(x0, min.getBlockY(), z0); + BiomeType biome = clipboard.getBiome(pt); + + String biomeKey = biome.getId(); + int biomeId; + if (palette.containsKey(biomeKey)) { + biomeId = palette.get(biomeKey); + } else { + biomeId = paletteMax; + palette.put(biomeKey, biomeId); + paletteMax++; + } + + while ((biomeId & -128) != 0) { + buffer.write(biomeId & 127 | 128); + biomeId >>>= 7; + } + buffer.write(biomeId); + } + } + + schematic.put("BiomePaletteMax", new IntTag(paletteMax)); + + Map paletteTag = new HashMap<>(); + palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value))); + + schematic.put("BiomePalette", new CompoundTag(paletteTag)); + schematic.put("BiomeData", new ByteArrayTag(buffer.toByteArray())); + } + + private void writeEntities(Clipboard clipboard, Map schematic) { + List entities = clipboard.getEntities().stream().map(e -> { + BaseEntity state = e.getState(); + if (state == null) { + return null; + } + Map values = Maps.newHashMap(); + CompoundTag rawData = state.getNbtData(); + if (rawData != null) { + values.putAll(rawData.getValue()); + } + values.remove("id"); + values.put("Id", new StringTag(state.getType().getId())); + final Location location = e.getLocation(); + values.put("Pos", writeVector(location.toVector())); + values.put("Rotation", writeRotation(location)); + + return new CompoundTag(values); + }).filter(Objects::nonNull).collect(Collectors.toList()); + if (entities.isEmpty()) { + return; + } + schematic.put("Entities", new ListTag(CompoundTag.class, entities)); + } + + private Tag writeVector(Vector3 vector) { + List list = new ArrayList<>(); + list.add(new DoubleTag(vector.getX())); + list.add(new DoubleTag(vector.getY())); + list.add(new DoubleTag(vector.getZ())); + return new ListTag(DoubleTag.class, list); + } + + private Tag writeRotation(Location location) { + List list = new ArrayList<>(); + list.add(new FloatTag(location.getYaw())); + list.add(new FloatTag(location.getPitch())); + return new ListTag(FloatTag.class, list); + } + + @Override + public void close() throws IOException { + outputStream.close(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java new file mode 100644 index 0000000..68f31e3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java @@ -0,0 +1,163 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.*; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler { + + private static final Property FacingProperty; + private static final Property RotationProperty; + + static { + Property tempFacing; + Property tempRotation; + try { + tempFacing = BlockTypes.WHITE_WALL_BANNER.getProperty("facing"); + tempRotation = BlockTypes.WHITE_BANNER.getProperty("rotation"); + } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { + tempFacing = null; + tempRotation = null; + } + FacingProperty = tempFacing; + RotationProperty = tempRotation; + } + + @Override + public > boolean isAffectedBlock(B block) { + return block.getBlockType() == BlockTypes.WHITE_BANNER + || block.getBlockType() == BlockTypes.WHITE_WALL_BANNER; + } + + @Override + public > BlockStateHolder updateNBT(B block, Map values) { + Tag typeTag = values.get("Base"); + if (typeTag instanceof IntTag) { + boolean isWall = block.getBlockType() == BlockTypes.WHITE_WALL_BANNER; + String bannerType = convertBannerType(((IntTag) typeTag).getValue(), isWall); + if (bannerType != null) { + BlockType type = BlockTypes.get("minecraft:" + bannerType); + if (type != null) { + BlockState state = type.getDefaultState(); + + if (isWall) { + Property facingProp = type.getProperty("facing"); + state = state.with(facingProp, block.getState(FacingProperty)); + } else { + Property rotationProp = type.getProperty("rotation"); + state = state.with(rotationProp, block.getState(RotationProperty)); + } + + values.remove("Base"); + + Tag patternsTag = values.get("Patterns"); + if (patternsTag instanceof ListTag) { + List tempList = new ArrayList<>(); + for (Tag pattern : ((ListTag) patternsTag).getValue()) { + if (pattern instanceof CompoundTag) { + Map patternMap = ((CompoundTag) pattern).getValue(); + Tag colorTag = patternMap.get("Color"); + + CompoundTagBuilder builder = CompoundTagBuilder.create(); + builder.putAll(patternMap); + if (colorTag instanceof IntTag) { + builder.putInt("Color", 15 - ((IntTag) colorTag).getValue()); + } + tempList.add(builder.build()); + } else { + tempList.add(pattern); + } + } + values.put("Patterns", new ListTag(((ListTag) patternsTag).getType(), tempList)); + } + return state; + } + } + } + return block; + } + + private static String convertBannerType(int oldType, boolean isWall) { + String color; + switch (oldType) { + case 0: + color = "black"; + break; + case 1: + color = "red"; + break; + case 2: + color = "green"; + break; + case 3: + color = "brown"; + break; + case 4: + color = "blue"; + break; + case 5: + color = "purple"; + break; + case 6: + color = "cyan"; + break; + case 7: + color = "light_gray"; + break; + case 8: + color = "gray"; + break; + case 9: + color = "pink"; + break; + case 10: + color = "lime"; + break; + case 11: + color = "yellow"; + break; + case 12: + color = "light_blue"; + break; + case 13: + color = "magenta"; + break; + case 14: + color = "orange"; + break; + case 15: + color = "white"; + break; + default: + return null; + } + return color + (isWall ? "_wall_banner" : "_banner"); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java new file mode 100644 index 0000000..d95c2ac --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java @@ -0,0 +1,141 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Map; + +@SuppressWarnings("") +public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler { + + private static final Property FACING_PROPERTY; + private static final Property PART_PROPERTY; + + static { + Property tempFacing; + Property tempPart; + try { + tempFacing = BlockTypes.RED_BED.getProperty("facing"); + tempPart = BlockTypes.RED_BED.getProperty("part"); + } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { + tempFacing = null; + tempPart = null; + } + FACING_PROPERTY = tempFacing; + PART_PROPERTY = tempPart; + } + + @Override + public > boolean isAffectedBlock(B block) { + return block.getBlockType() == BlockTypes.RED_BED; + } + + @Override + public > BlockStateHolder updateNBT(B block, Map values) { + Tag typeTag = values.get("color"); + if (typeTag instanceof IntTag) { + String bedType = convertBedType(((IntTag) typeTag).getValue()); + if (bedType != null) { + BlockType type = BlockTypes.get("minecraft:" + bedType); + if (type != null) { + BlockState state = type.getDefaultState(); + + Property facingProp = type.getProperty("facing"); + state = state.with(facingProp, block.getState(FACING_PROPERTY)); + + Property occupiedProp = type.getProperty("occupied"); + state = state.with(occupiedProp, false); + + Property partProp = type.getProperty("part"); + state = state.with(partProp, block.getState(PART_PROPERTY)); + + values.remove("color"); + return state; + } + } + } + return block; + } + + private String convertBedType(int oldType) { + String color; + switch (oldType) { + case 0: + color = "white"; + break; + case 1: + color = "orange"; + break; + case 2: + color = "magenta"; + break; + case 3: + color = "light_blue"; + break; + case 4: + color = "yellow"; + break; + case 5: + color = "lime"; + break; + case 6: + color = "pink"; + break; + case 7: + color = "gray"; + break; + case 8: + color = "light_gray"; + break; + case 9: + color = "cyan"; + break; + case 10: + color = "purple"; + break; + case 11: + color = "blue"; + break; + case 12: + color = "brown"; + break; + case 13: + color = "green"; + break; + case 14: + color = "red"; + break; + case 15: + color = "black"; + break; + default: + return null; + } + return color + "_bed"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java new file mode 100644 index 0000000..12c26f0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java @@ -0,0 +1,29 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.entity.EntityType; + +public interface EntityNBTCompatibilityHandler { + boolean isAffectedEntity(EntityType type, CompoundTag entityTag); + + CompoundTag updateNBT(EntityType type, CompoundTag entityTag); +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java new file mode 100644 index 0000000..f497796 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java @@ -0,0 +1,97 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.registry.LegacyMapper; + +import java.util.Map; + +public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { + @Override + public > boolean isAffectedBlock(B block) { + return block.getBlockType() == BlockTypes.FLOWER_POT; + } + + @Override + public > BlockStateHolder updateNBT(B block, Map values) { + Tag item = values.get("Item"); + if (item instanceof StringTag) { + String id = ((StringTag) item).getValue(); + if (id.isEmpty()) { + return BlockTypes.FLOWER_POT.getDefaultState(); + } + int data = 0; + Tag dataTag = values.get("Data"); + if (dataTag instanceof IntTag) { + data = ((IntTag) dataTag).getValue(); + } + BlockState newState = convertLegacyBlockType(id, data); + if (newState != null) { + values.clear(); + return newState; + } + } + return block; + } + + private BlockState convertLegacyBlockType(String id, int data) { + int newId = 0; + switch (id) { + case "minecraft:red_flower": + newId = 38; // now poppy + break; + case "minecraft:yellow_flower": + newId = 37; // now dandelion + break; + case "minecraft:sapling": + newId = 6; // oak_sapling + break; + case "minecraft:deadbush": + case "minecraft:tallgrass": + newId = 31; // dead_bush with fern and grass (not 32!) + break; + default: + break; + } + String plantedName = null; + if (newId == 0 && id.startsWith("minecraft:")) { + plantedName = id.substring(10); + } else { + BlockState plantedWithData = LegacyMapper.getInstance().getBlockFromLegacy(newId, data); + if (plantedWithData != null) { + plantedName = plantedWithData.getBlockType().getId().substring(10); // remove "minecraft:" + } + } + if (plantedName != null) { + BlockType potAndPlanted = BlockTypes.get("minecraft:potted_" + plantedName); + if (potAndPlanted != null) { + return potAndPlanted.getDefaultState(); + } + } + return null; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java new file mode 100644 index 0000000..efded28 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java @@ -0,0 +1,31 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.Map; + +public interface NBTCompatibilityHandler { + > boolean isAffectedBlock(B block); + + > BlockStateHolder updateNBT(B block, Map values); +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java new file mode 100644 index 0000000..01d01cc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java @@ -0,0 +1,63 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.registry.state.IntegerProperty; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Map; + +public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { + private static final IntegerProperty NoteProperty; + + static { + IntegerProperty temp; + try { + temp = (IntegerProperty) (Property) BlockTypes.NOTE_BLOCK.getProperty("note"); + } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { + temp = null; + } + NoteProperty = temp; + } + + @Override + public > boolean isAffectedBlock(B block) { + return NoteProperty != null && block.getBlockType() == BlockTypes.NOTE_BLOCK; + } + + @Override + public > BlockStateHolder updateNBT(B block, Map values) { + // note that instrument was not stored (in state or nbt) previously. + // it will be updated to the block below when it gets set into the world for the first time + Tag noteTag = values.get("note"); + if (noteTag instanceof ByteTag) { + Byte note = ((ByteTag) noteTag).getValue(); + if (note != null) { + values.clear(); + return block.with(NoteProperty, (int) note).toImmutableState(); + } + } + return block; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java new file mode 100644 index 0000000..2545704 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.CompoundTagBuilder; +import com.sk89q.worldedit.internal.helper.MCDirections; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.entity.EntityType; + +public class Pre13HangingCompatibilityHandler implements EntityNBTCompatibilityHandler { + + @Override + public boolean isAffectedEntity(EntityType type, CompoundTag tag) { + if (!type.getId().startsWith("minecraft:")) { + return false; + } + boolean hasLegacyDirection = tag.containsKey("Dir") || tag.containsKey("Direction"); + boolean hasFacing = tag.containsKey("Facing"); + return hasLegacyDirection || hasFacing; + } + + @Override + public CompoundTag updateNBT(EntityType type, CompoundTag tag) { + boolean hasLegacyDir = tag.containsKey("Dir"); + boolean hasLegacyDirection = tag.containsKey("Direction"); + boolean hasPre113Facing = tag.containsKey("Facing"); + Direction newDirection; + if (hasLegacyDir) { + newDirection = MCDirections.fromPre13Hanging(MCDirections.fromLegacyHanging((byte) tag.asInt("Dir"))); + } else if (hasLegacyDirection) { + newDirection = MCDirections.fromPre13Hanging(tag.asInt("Direction")); + } else if (hasPre113Facing) { + newDirection = MCDirections.fromPre13Hanging(tag.asInt("Facing")); + } else { + return tag; + } + byte hangingByte = (byte) MCDirections.toHanging(newDirection); + CompoundTagBuilder builder = tag.createBuilder(); + builder.putByte("Facing", hangingByte); + return builder.build(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java new file mode 100644 index 0000000..49a5231 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java @@ -0,0 +1,70 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.google.gson.*; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.Map; + +public class SignCompatibilityHandler implements NBTCompatibilityHandler { + + @Override + public > boolean isAffectedBlock(B block) { + return DeprecationUtil.isSign(block.getBlockType()); + } + + @Override + public > BlockStateHolder updateNBT(B block, Map values) { + for (int i = 0; i < 4; ++i) { + String key = "Text" + (i + 1); + Tag value = values.get(key); + if (value instanceof StringTag) { + String storedString = ((StringTag) value).getValue(); + JsonElement jsonElement = null; + if (storedString != null && storedString.startsWith("{")) { + try { + jsonElement = new JsonParser().parse(storedString); + } catch (JsonSyntaxException ex) { + // ignore: jsonElement will be null in the next check + } + } + if (jsonElement == null) { + jsonElement = new JsonPrimitive(storedString == null ? "" : storedString); + } + if (jsonElement.isJsonObject()) { + continue; + } + + if (jsonElement.isJsonNull()) { + jsonElement = new JsonPrimitive(""); + } + + JsonObject jsonTextObject = new JsonObject(); + jsonTextObject.add("text", jsonElement); + values.put("Text" + (i + 1), new StringTag(jsonTextObject.toString())); + } + } + return block; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java new file mode 100644 index 0000000..b728102 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java @@ -0,0 +1,100 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Map; + +public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler { + + private static final Property FacingProperty; + + static { + Property tempFacing; + try { + tempFacing = BlockTypes.SKELETON_WALL_SKULL.getProperty("facing"); + } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { + tempFacing = null; + } + FacingProperty = tempFacing; + } + + @Override + public > boolean isAffectedBlock(B block) { + return block.getBlockType() == BlockTypes.SKELETON_SKULL + || block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL; + } + + @Override + public > BlockStateHolder updateNBT(B block, Map values) { + boolean isWall = block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL; + Tag typeTag = values.get("SkullType"); + if (typeTag instanceof ByteTag) { + String skullType = convertSkullType(((ByteTag) typeTag).getValue(), isWall); + if (skullType != null) { + BlockType type = BlockTypes.get("minecraft:" + skullType); + if (type != null) { + BlockState state = type.getDefaultState(); + if (isWall) { + Property newProp = type.getProperty("facing"); + state = state.with(newProp, block.getState(FacingProperty)); + } else { + Tag rotTag = values.get("Rot"); + if (rotTag instanceof ByteTag) { + Property newProp = type.getProperty("rotation"); + state = state.with(newProp, (int) ((ByteTag) rotTag).getValue()); + } + } + values.remove("SkullType"); + values.remove("Rot"); + return state; + } + } + } + return block; + } + + private String convertSkullType(Byte oldType, boolean isWall) { + switch (oldType) { + case 0: + return isWall ? "skeleton_wall_skull" : "skeleton_skull"; + case 1: + return isWall ? "wither_skeleton_wall_skull" : "wither_skeleton_skull"; + case 2: + return isWall ? "zombie_wall_head" : "zombie_head"; + case 3: + return isWall ? "player_wall_head" : "player_head"; + case 4: + return isWall ? "creeper_wall_head" : "creeper_head"; + case 5: + return isWall ? "dragon_wall_head" : "dragon_head"; + default: + return null; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java new file mode 100644 index 0000000..fb34aaf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java @@ -0,0 +1,132 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.inventory; + +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.block.BlockState; + +/** + * Represents a source to get blocks from and store removed ones. + */ +public abstract class BlockBag { + + /** + * Stores a block as if it was mined. + * + * @param blockState the block state + * @throws BlockBagException on error + */ + public void storeDroppedBlock(BlockState blockState) throws BlockBagException { + BlockState dropped = blockState; // TODO BlockType.getBlockBagItem(id, data); + if (dropped == null) { + return; + } + if (dropped.getBlockType().getMaterial().isAir()) { + return; + } + + storeBlock(dropped); + } + + /** + * Sets a block as if it was placed by hand. + * + * @param blockState The block state + * @throws BlockBagException on error + */ + public void fetchPlacedBlock(BlockState blockState) throws BlockBagException { + try { + // Blocks that can't be fetched... + if (blockState.getBlockType().getMaterial().isReplacedDuringPlacement()) { + return; + } + fetchBlock(blockState); + } catch (OutOfBlocksException e) { + BlockState placed = blockState; // TODO BlockType.getBlockBagItem(id, data); + if (placed.getBlockType().getMaterial().isAir()) { + throw e; // TODO: check + } + + fetchBlock(placed); + } + } + + /** + * Get a block. + * + * @param blockState the block state + * @throws BlockBagException on error + */ + public abstract void fetchBlock(BlockState blockState) throws BlockBagException; + + /** + * Store a block. + * + * @param blockState The block state + * @throws BlockBagException on error + */ + public void storeBlock(BlockState blockState) throws BlockBagException { + this.storeBlock(blockState, 1); + } + + /** + * Store a block. + * + * @param blockState The block state + * @param amount The amount + * @throws BlockBagException on error + */ + public abstract void storeBlock(BlockState blockState, int amount) throws BlockBagException; + + /** + * Checks to see if a block exists without removing it. + * + * @param blockState the block state + * @return whether the block exists + */ + public boolean peekBlock(BlockState blockState) { + try { + fetchBlock(blockState); + storeBlock(blockState); + return true; + } catch (BlockBagException e) { + return false; + } + } + + /** + * Flush any changes. This is called at the end. + */ + public abstract void flushChanges(); + + /** + * Adds a position to be used a source. + * + * @param pos the position + */ + public abstract void addSourcePosition(Location pos); + + /** + * Adds a position to be used a source. + * + * @param pos the position + */ + public abstract void addSingleSourcePosition(Location pos); +} diff --git a/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagException.java b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagException.java new file mode 100644 index 0000000..2627d38 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagException.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.inventory; + +/** + * Thrown when a block bag detects a problem. + */ +public class BlockBagException extends Exception { +} diff --git a/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java new file mode 100644 index 0000000..8e1aadc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java @@ -0,0 +1,115 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.inventory; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * Applies a {@link BlockBag} to operations. + */ +public class BlockBagExtent extends AbstractDelegateExtent { + + private Map missingBlocks = new HashMap<>(); + private BlockBag blockBag; + + /** + * Create a new instance. + * + * @param extent the extent + * @param blockBag the block bag + */ + public BlockBagExtent(Extent extent, @Nullable BlockBag blockBag) { + super(extent); + this.blockBag = blockBag; + } + + /** + * Get the block bag. + * + * @return a block bag, which may be null if none is used + */ + public @Nullable BlockBag getBlockBag() { + return blockBag; + } + + /** + * Set the block bag. + * + * @param blockBag a block bag, which may be null if none is used + */ + public void setBlockBag(@Nullable BlockBag blockBag) { + this.blockBag = blockBag; + } + + /** + * Gets the list of missing blocks and clears the list for the next + * operation. + * + * @return a map of missing blocks + */ + public Map popMissing() { + Map missingBlocks = this.missingBlocks; + this.missingBlocks = new HashMap<>(); + return missingBlocks; + } + + @Override + public > boolean setBlock(BlockVector3 position, B block) throws WorldEditException { + if (blockBag != null) { + BlockState existing = getExtent().getBlock(position); + + if (!block.getBlockType().equals(existing.getBlockType())) { + if (!block.getBlockType().getMaterial().isAir()) { + try { + blockBag.fetchPlacedBlock(block.toImmutableState()); + } catch (UnplaceableBlockException e) { + return false; + } catch (BlockBagException e) { + if (!missingBlocks.containsKey(block.getBlockType())) { + missingBlocks.put(block.getBlockType(), 1); + } else { + missingBlocks.put(block.getBlockType(), missingBlocks.get(block.getBlockType()) + 1); + } + return false; + } + } + + if (!existing.getBlockType().getMaterial().isAir()) { + try { + blockBag.storeDroppedBlock(existing); + } catch (BlockBagException ignored) { + } + } + } + } + + return super.setBlock(position, block); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/inventory/OutOfBlocksException.java b/src/main/java/com/sk89q/worldedit/extent/inventory/OutOfBlocksException.java new file mode 100644 index 0000000..ede4b6c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/OutOfBlocksException.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.inventory; + +/** + * Thrown when there are no more blocks left. + */ +public class OutOfBlocksException extends BlockBagException { +} diff --git a/src/main/java/com/sk89q/worldedit/extent/inventory/OutOfSpaceException.java b/src/main/java/com/sk89q/worldedit/extent/inventory/OutOfSpaceException.java new file mode 100644 index 0000000..a9cc04f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/OutOfSpaceException.java @@ -0,0 +1,48 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.inventory; + +import com.sk89q.worldedit.world.block.BlockType; + +/** + * Thrown when the target inventory of a block bag is full. + */ +public class OutOfSpaceException extends BlockBagException { + + private final BlockType type; + + /** + * Construct the object. + * + * @param type the type of the block + */ + public OutOfSpaceException(BlockType type) { + this.type = type; + } + + /** + * Get the type of the block. + * + * @return the type + */ + public BlockType getType() { + return this.type; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/inventory/UnplaceableBlockException.java b/src/main/java/com/sk89q/worldedit/extent/inventory/UnplaceableBlockException.java new file mode 100644 index 0000000..21d95ee --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/UnplaceableBlockException.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.inventory; + +/** + * Thrown when a block that can't be placed is used. + */ +public class UnplaceableBlockException extends BlockBagException { +} diff --git a/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java b/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java new file mode 100644 index 0000000..181baf3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java @@ -0,0 +1,115 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.reorder; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractBufferingExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.internal.util.RegionOptimizedVectorSorter; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.collection.BlockMap; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * A special extent that batches changes into Minecraft chunks. This helps + * improve the speed of setting the blocks, since chunks do not need to be + * loaded repeatedly, however it does take more memory due to caching the + * blocks. + */ +public class ChunkBatchingExtent extends AbstractBufferingExtent { + + private final BlockMap blockMap = BlockMap.createForBaseBlock(); + private boolean enabled; + + public ChunkBatchingExtent(Extent extent) { + this(extent, true); + } + + public ChunkBatchingExtent(Extent extent, boolean enabled) { + super(extent); + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean commitRequired() { + return enabled; + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + if (!enabled) { + return setDelegateBlock(location, block); + } + blockMap.put(location, block.toBaseBlock()); + return true; + } + + @Override + protected BaseBlock getBufferedFullBlock(BlockVector3 position) { + return blockMap.get(position); + } + + @Override + protected Operation commitBefore() { + if (!commitRequired()) { + return null; + } + return new Operation() { + + // we get modified between create/resume -- only create this on resume to prevent CME + private Iterator iterator; + + @Override + public Operation resume(RunContext run) throws WorldEditException { + if (iterator == null) { + List blockVectors = new ArrayList<>(blockMap.keySet()); + RegionOptimizedVectorSorter.sort(blockVectors); + iterator = blockVectors.iterator(); + } + while (iterator.hasNext()) { + BlockVector3 position = iterator.next(); + BaseBlock block = blockMap.get(position); + getExtent().setBlock(position, block); + } + blockMap.clear(); + return null; + } + + @Override + public void cancel() { + } + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java b/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java new file mode 100644 index 0000000..1259432 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java @@ -0,0 +1,286 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.reorder; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractBufferingExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.OperationQueue; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.function.operation.SetBlockMap; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.collection.BlockMap; +import com.sk89q.worldedit.world.block.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Re-orders blocks into several stages. + */ +public class MultiStageReorder extends AbstractBufferingExtent implements ReorderingExtent { + + private static final Map priorityMap = new HashMap<>(); + + static { + // Late + priorityMap.put(BlockTypes.WATER, PlacementPriority.LATE); + priorityMap.put(BlockTypes.LAVA, PlacementPriority.LATE); + priorityMap.put(BlockTypes.SAND, PlacementPriority.LATE); + priorityMap.put(BlockTypes.GRAVEL, PlacementPriority.LATE); + + // Late + BlockCategories.SAPLINGS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + BlockCategories.FLOWER_POTS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + BlockCategories.BUTTONS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + BlockCategories.ANVIL.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + BlockCategories.WOODEN_PRESSURE_PLATES.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + // Keeping CARPETS for pre-1.19 compatibility + @SuppressWarnings("deprecation") + BlockCategory carpets = BlockCategories.CARPETS; + carpets.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + BlockCategories.WOOL_CARPETS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + BlockCategories.RAILS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + BlockCategories.BEDS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + BlockCategories.SMALL_FLOWERS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + priorityMap.put(BlockTypes.BLACK_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.BLUE_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.BROWN_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.CYAN_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.GRAY_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.GREEN_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.LIGHT_BLUE_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.LIGHT_GRAY_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.LIME_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.MAGENTA_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.ORANGE_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.PINK_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.PURPLE_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.RED_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.WHITE_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.YELLOW_BED, PlacementPriority.LAST); + priorityMap.put(BlockTypes.GRASS, PlacementPriority.LAST); + priorityMap.put(BlockTypes.TALL_GRASS, PlacementPriority.LAST); + priorityMap.put(BlockTypes.ROSE_BUSH, PlacementPriority.LAST); + priorityMap.put(BlockTypes.DANDELION, PlacementPriority.LAST); + priorityMap.put(BlockTypes.BROWN_MUSHROOM, PlacementPriority.LAST); + priorityMap.put(BlockTypes.RED_MUSHROOM, PlacementPriority.LAST); + priorityMap.put(BlockTypes.FERN, PlacementPriority.LAST); + priorityMap.put(BlockTypes.LARGE_FERN, PlacementPriority.LAST); + priorityMap.put(BlockTypes.OXEYE_DAISY, PlacementPriority.LAST); + priorityMap.put(BlockTypes.AZURE_BLUET, PlacementPriority.LAST); + priorityMap.put(BlockTypes.TORCH, PlacementPriority.LAST); + priorityMap.put(BlockTypes.WALL_TORCH, PlacementPriority.LAST); + priorityMap.put(BlockTypes.FIRE, PlacementPriority.LAST); + priorityMap.put(BlockTypes.REDSTONE_WIRE, PlacementPriority.LAST); + priorityMap.put(BlockTypes.CARROTS, PlacementPriority.LAST); + priorityMap.put(BlockTypes.POTATOES, PlacementPriority.LAST); + priorityMap.put(BlockTypes.WHEAT, PlacementPriority.LAST); + priorityMap.put(BlockTypes.BEETROOTS, PlacementPriority.LAST); + priorityMap.put(BlockTypes.COCOA, PlacementPriority.LAST); + priorityMap.put(BlockTypes.LADDER, PlacementPriority.LAST); + priorityMap.put(BlockTypes.LEVER, PlacementPriority.LAST); + priorityMap.put(BlockTypes.REDSTONE_TORCH, PlacementPriority.LAST); + priorityMap.put(BlockTypes.REDSTONE_WALL_TORCH, PlacementPriority.LAST); + priorityMap.put(BlockTypes.SNOW, PlacementPriority.LAST); + priorityMap.put(BlockTypes.NETHER_PORTAL, PlacementPriority.LAST); + priorityMap.put(BlockTypes.END_PORTAL, PlacementPriority.LAST); + priorityMap.put(BlockTypes.REPEATER, PlacementPriority.LAST); + priorityMap.put(BlockTypes.VINE, PlacementPriority.LAST); + priorityMap.put(BlockTypes.LILY_PAD, PlacementPriority.LAST); + priorityMap.put(BlockTypes.NETHER_WART, PlacementPriority.LAST); + priorityMap.put(BlockTypes.PISTON, PlacementPriority.LAST); + priorityMap.put(BlockTypes.STICKY_PISTON, PlacementPriority.LAST); + priorityMap.put(BlockTypes.TRIPWIRE_HOOK, PlacementPriority.LAST); + priorityMap.put(BlockTypes.TRIPWIRE, PlacementPriority.LAST); + priorityMap.put(BlockTypes.STONE_PRESSURE_PLATE, PlacementPriority.LAST); + priorityMap.put(BlockTypes.HEAVY_WEIGHTED_PRESSURE_PLATE, PlacementPriority.LAST); + priorityMap.put(BlockTypes.LIGHT_WEIGHTED_PRESSURE_PLATE, PlacementPriority.LAST); + priorityMap.put(BlockTypes.COMPARATOR, PlacementPriority.LAST); + priorityMap.put(BlockTypes.IRON_TRAPDOOR, PlacementPriority.LAST); + priorityMap.put(BlockTypes.ACACIA_TRAPDOOR, PlacementPriority.LAST); + priorityMap.put(BlockTypes.BIRCH_TRAPDOOR, PlacementPriority.LAST); + priorityMap.put(BlockTypes.DARK_OAK_TRAPDOOR, PlacementPriority.LAST); + priorityMap.put(BlockTypes.JUNGLE_TRAPDOOR, PlacementPriority.LAST); + priorityMap.put(BlockTypes.OAK_TRAPDOOR, PlacementPriority.LAST); + priorityMap.put(BlockTypes.SPRUCE_TRAPDOOR, PlacementPriority.LAST); + priorityMap.put(BlockTypes.DAYLIGHT_DETECTOR, PlacementPriority.LAST); + priorityMap.put(BlockTypes.CAKE, PlacementPriority.LAST); + + // Final + BlockCategories.DOORS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.FINAL)); + BlockCategories.BANNERS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.FINAL)); + BlockCategories.SIGNS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.FINAL)); + // Keeping sign and wall_sign for 1.13 compatibility + @SuppressWarnings("deprecation") + BlockType sign = BlockTypes.SIGN; + priorityMap.put(sign, PlacementPriority.FINAL); + @SuppressWarnings("deprecation") + BlockType wallSign = BlockTypes.WALL_SIGN; + priorityMap.put(wallSign, PlacementPriority.FINAL); + priorityMap.put(BlockTypes.CACTUS, PlacementPriority.FINAL); + priorityMap.put(BlockTypes.SUGAR_CANE, PlacementPriority.FINAL); + priorityMap.put(BlockTypes.PISTON_HEAD, PlacementPriority.FINAL); + priorityMap.put(BlockTypes.MOVING_PISTON, PlacementPriority.FINAL); + } + + private final Map> stages = new HashMap<>(); + + private boolean enabled; + + public enum PlacementPriority { + CLEAR_FINAL, + CLEAR_LAST, + CLEAR_LATE, + FIRST, + LATE, + LAST, + FINAL + } + + /** + * Create a new instance when the re-ordering is enabled. + * + * @param extent the extent + */ + public MultiStageReorder(Extent extent) { + this(extent, true); + } + + /** + * Create a new instance. + * + * @param extent the extent + * @param enabled true to enable + */ + public MultiStageReorder(Extent extent, boolean enabled) { + super(extent); + this.enabled = enabled; + + for (PlacementPriority priority : PlacementPriority.values()) { + stages.put(priority, BlockMap.createForBaseBlock()); + } + } + + /** + * Return whether re-ordering is enabled. + * + * @return true if re-ordering is enabled + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Set whether re-ordering is enabled. + * + * @param enabled true if re-ordering is enabled + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean commitRequired() { + return enabled; + } + + /** + * Gets the stage priority of the block. + * + * @param block The block + * @return The priority + */ + private > PlacementPriority getPlacementPriority(B block) { + return priorityMap.getOrDefault(block.getBlockType(), PlacementPriority.FIRST); + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + if (!enabled) { + return setDelegateBlock(location, block); + } + + BlockState existing = getExtent().getBlock(location); + PlacementPriority priority = getPlacementPriority(block); + PlacementPriority srcPriority = getPlacementPriority(existing); + + if (srcPriority != PlacementPriority.FIRST) { + BaseBlock replacement = (block.getBlockType().getMaterial().isAir() ? block : BlockTypes.AIR.getDefaultState()).toBaseBlock(); + + switch (srcPriority) { + case FINAL: + stages.get(PlacementPriority.CLEAR_FINAL).put(location, replacement); + break; + case LATE: + stages.get(PlacementPriority.CLEAR_LATE).put(location, replacement); + break; + case LAST: + stages.get(PlacementPriority.CLEAR_LAST).put(location, replacement); + break; + default: + break; + } + + if (block.getBlockType().getMaterial().isAir()) { + return !existing.equalsFuzzy(block); + } + } + + stages.get(priority).put(location, block.toBaseBlock()); + return !existing.equalsFuzzy(block); + } + + @Override + protected BaseBlock getBufferedFullBlock(BlockVector3 position) { + for (BlockMap blocks : stages.values()) { + BaseBlock baseBlock = blocks.get(position); + if (baseBlock != null) { + return baseBlock; + } + } + return null; + } + + @Override + public Operation commitBefore() { + if (!commitRequired()) { + return null; + } + List operations = new ArrayList<>(); + for (PlacementPriority priority : PlacementPriority.values()) { + BlockMap blocks = stages.get(priority); + operations.add(new SetBlockMap(getExtent(), blocks) { + @Override + public Operation resume(RunContext run) throws WorldEditException { + Operation operation = super.resume(run); + if (operation == null) { + blocks.clear(); + } + return operation; + } + }); + } + + return new OperationQueue(operations); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/reorder/ReorderingExtent.java b/src/main/java/com/sk89q/worldedit/extent/reorder/ReorderingExtent.java new file mode 100644 index 0000000..e19e766 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/reorder/ReorderingExtent.java @@ -0,0 +1,34 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.reorder; + +import com.sk89q.worldedit.extent.Extent; + +/** + * An interface for {@link Extent}s that are meant to reorder changes so + * that they are more successful. + * + *

For example, torches in Minecraft need to be placed on a block. A smart + * reordering implementation might place the torch after the block has + * been placed.

+ */ +public interface ReorderingExtent extends Extent { + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java new file mode 100644 index 0000000..e559899 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -0,0 +1,315 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.transform; + +import com.google.common.collect.Sets; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.registry.state.BooleanProperty; +import com.sk89q.worldedit.registry.state.DirectionalProperty; +import com.sk89q.worldedit.registry.state.EnumProperty; +import com.sk89q.worldedit.registry.state.IntegerProperty; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.Set; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Transforms blocks themselves (but not their position) according to a + * given transform. + */ +public class BlockTransformExtent extends AbstractDelegateExtent { + + private final Transform transform; + + /** + * Create a new instance. + * + * @param extent the extent + */ + public BlockTransformExtent(Extent extent, Transform transform) { + super(extent); + checkNotNull(transform); + this.transform = transform; + } + + /** + * Get the transform. + * + * @return the transform + */ + public Transform getTransform() { + return transform; + } + + /** + * Transform a block without making a copy. + * + * @param block the block + * @param reverse true to transform in the opposite direction + * @return the same block + */ + private > T transformBlock(T block, boolean reverse) { + return transform(block, reverse ? transform.inverse() : transform); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return transformBlock(super.getBlock(position), false); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return transformBlock(super.getFullBlock(position), false); + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + return super.setBlock(location, transformBlock(block, true)); + } + + private static final Set directionNames = Sets.newHashSet("north", "south", "east", "west"); + + /** + * Transform the given block using the given transform. + * + *

The provided block is not modified.

+ * + * @param block the block + * @param transform the transform + * @return the same block + */ + public static > B transform(B block, Transform transform) { + checkNotNull(block); + checkNotNull(transform); + + B result = block; + List> properties = block.getBlockType().getProperties(); + + for (Property property : properties) { + if (property instanceof DirectionalProperty) { + DirectionalProperty dirProp = (DirectionalProperty) property; + Direction value = (Direction) block.getState(property); + if (value != null) { + Vector3 newValue = getNewStateValue(dirProp.getValues(), transform, value.toVector()); + if (newValue != null) { + result = result.with(dirProp, Direction.findClosest(newValue, Direction.Flag.ALL)); + } + } + } else if (property instanceof EnumProperty) { + EnumProperty enumProp = (EnumProperty) property; + if (property.getName().equals("axis")) { + // We have an axis - this is something we can do the rotations to :sunglasses: + Direction value = null; + switch ((String) block.getState(property)) { + case "x": + value = Direction.EAST; + break; + case "y": + value = Direction.UP; + break; + case "z": + value = Direction.NORTH; + break; + default: + break; + } + if (value != null) { + Vector3 newValue = getNewStateValue(Direction.valuesOf(Direction.Flag.UPRIGHT | Direction.Flag.CARDINAL), transform, value.toVector()); + if (newValue != null) { + String axis = null; + Direction newDir = Direction.findClosest(newValue, Direction.Flag.UPRIGHT | Direction.Flag.CARDINAL); + if (newDir == Direction.NORTH || newDir == Direction.SOUTH) { + axis = "z"; + } else if (newDir == Direction.EAST || newDir == Direction.WEST) { + axis = "x"; + } else if (newDir == Direction.UP || newDir == Direction.DOWN) { + axis = "y"; + } + if (axis != null) { + result = result.with(enumProp, axis); + } + } + } + } else if (property.getName().equals("type") && transform instanceof AffineTransform) { + // chests + if (((AffineTransform) transform).isHorizontalFlip()) { + String value = (String) block.getState(property); + String newValue = null; + if ("left".equals(value)) { + newValue = "right"; + } else if ("right".equals(value)) { + newValue = "left"; + } + if (newValue != null && enumProp.getValues().contains(newValue)) { + result = result.with(enumProp, newValue); + } + } + // slabs + if (((AffineTransform) transform).isVerticalFlip()) { + String value = (String) block.getState(property); + String newValue = null; + if ("bottom".equals(value)) { + newValue = "top"; + } else if ("top".equals(value)) { + newValue = "bottom"; + } + if (newValue != null && enumProp.getValues().contains(newValue)) { + result = result.with(enumProp, newValue); + } + } + } else if (property.getName().equals("half") && transform instanceof AffineTransform) { + // stairs + if (((AffineTransform) transform).isVerticalFlip()) { + String value = (String) block.getState(property); + String newValue = null; + if ("bottom".equals(value)) { + newValue = "top"; + } else if ("top".equals(value)) { + newValue = "bottom"; + } + if (newValue != null && enumProp.getValues().contains(newValue)) { + result = result.with(enumProp, newValue); + } + } + } else if (property.getName().equals("shape") && transform instanceof AffineTransform) { + // stairs + if (((AffineTransform) transform).isHorizontalFlip()) { + String value = (String) block.getState(property); + String newValue = null; + if ("outer_left".equals(value)) { + newValue = "outer_right"; + } else if ("outer_right".equals(value)) { + newValue = "outer_left"; + } else if ("inner_left".equals(value)) { + newValue = "inner_right"; + } else if ("inner_right".equals(value)) { + newValue = "inner_left"; + } + if (newValue != null && enumProp.getValues().contains(newValue)) { + result = result.with(enumProp, newValue); + } + } + } + } else if (property instanceof IntegerProperty) { + IntegerProperty intProp = (IntegerProperty) property; + if (property.getName().equals("rotation")) { + if (intProp.getValues().size() == 16) { + Optional direction = Direction.fromRotationIndex(block.getState(intProp)); + int horizontalFlags = Direction.Flag.CARDINAL | Direction.Flag.ORDINAL | Direction.Flag.SECONDARY_ORDINAL; + if (direction.isPresent()) { + Vector3 vec = getNewStateValue(Direction.valuesOf(horizontalFlags), transform, direction.get().toVector()); + if (vec != null) { + OptionalInt newRotation = Direction.findClosest(vec, horizontalFlags).toRotationIndex(); + if (newRotation.isPresent()) { + result = result.with(intProp, newRotation.getAsInt()); + } + } + } + } + } + } + } + + Map directionalProperties = new HashMap<>(); + for (Property prop : properties) { + if (directionNames.contains(prop.getName())) { + if (prop instanceof BooleanProperty && (Boolean) block.getState(prop) + || prop instanceof EnumProperty && !block.getState(prop).toString().equals("none")) { + String origProp = prop.getName().toUpperCase(Locale.ROOT); + Direction dir = Direction.valueOf(origProp); + Direction closest = Direction.findClosest(transform.apply(dir.toVector()), Direction.Flag.CARDINAL); + if (closest != null) { + String closestProp = closest.name().toLowerCase(Locale.ROOT); + if (prop instanceof BooleanProperty) { + result = result.with((BooleanProperty) prop, Boolean.FALSE); + directionalProperties.put(closestProp, Boolean.TRUE); + } else { + if (prop.getValues().contains("none")) { + @SuppressWarnings("unchecked") + Property propAsObj = (Property) prop; + result = result.with(propAsObj, "none"); + } + directionalProperties.put(closestProp, block.getState(prop)); + } + } + } + } + } + + if (!directionalProperties.isEmpty()) { + for (String directionName : directionNames) { + Property dirProp = block.getBlockType().getProperty(directionName); + result = result.with(dirProp, directionalProperties.get(directionName)); + } + } + + return result; + } + + /** + * Get the new value with the transformed direction. + * + * @param allowedStates the allowed states + * @param transform the transform + * @param oldDirection the old direction to transform + * @return a new state or null if none could be found + */ + @Nullable + private static Vector3 getNewStateValue(List allowedStates, Transform transform, Vector3 oldDirection) { + Vector3 newDirection = transform.apply(oldDirection).subtract(transform.apply(Vector3.ZERO)).normalize(); + Vector3 newValue = null; + double closest = -2; + boolean found = false; + + for (Direction v : allowedStates) { + double dot = v.toVector().normalize().dot(newDirection); + if (dot >= closest) { + closest = dot; + newValue = v.toVector(); + found = true; + } + } + + if (found) { + return newValue; + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java b/src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java new file mode 100644 index 0000000..dd93c85 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java @@ -0,0 +1,89 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.validation; + +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Limits the number of blocks that can be changed before a + * {@link MaxChangedBlocksException} is thrown. + */ +public class BlockChangeLimiter extends AbstractDelegateExtent { + + private int limit; + private int count = 0; + + /** + * Create a new instance. + * + * @param extent the extent + * @param limit the limit (>= 0) or -1 for no limit + */ + public BlockChangeLimiter(Extent extent, int limit) { + super(extent); + setLimit(limit); + } + + /** + * Get the limit. + * + * @return the limit (>= 0) or -1 for no limit + */ + public int getLimit() { + return limit; + } + + /** + * Set the limit. + * + * @param limit the limit (>= 0) or -1 for no limit + */ + public void setLimit(int limit) { + checkArgument(limit >= -1, "limit >= -1 required"); + this.limit = limit; + } + + /** + * Get the number of blocks that have been counted so far. + * + * @return the number of blocks + */ + public int getCount() { + return count; + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + if (limit >= 0) { + if (count >= limit) { + throw new MaxChangedBlocksException(limit); + } + count++; + } + return super.setBlock(location, block); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java b/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java new file mode 100644 index 0000000..4fe7ea7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java @@ -0,0 +1,78 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.validation; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Validates set data to prevent creating invalid blocks and such. + */ +public class DataValidatorExtent extends AbstractDelegateExtent { + + private final World world; + + /** + * Create a new instance. + * + * @param extent the extent + * @param world the world + */ + public DataValidatorExtent(Extent extent, World world) { + super(extent); + checkNotNull(world); + this.world = world; + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + final int y = location.getBlockY(); + final BlockType type = block.getBlockType(); + if (y < world.getMinY() || y > world.getMaxY()) { + return false; + } + + // No invalid blocks + if (type == null) { + return false; + } + + return super.setBlock(location, block); + } + + @Override + public boolean setBiome(BlockVector3 location, BiomeType biome) { + final int y = location.getBlockY(); + + if (y < world.getMinY() || y > world.getMaxY()) { + return false; + } + + return super.setBiome(location, biome); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/world/BiomeQuirkExtent.java b/src/main/java/com/sk89q/worldedit/extent/world/BiomeQuirkExtent.java new file mode 100644 index 0000000..1abdccf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/world/BiomeQuirkExtent.java @@ -0,0 +1,50 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.world; + +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; + +/** + * Handles quirks when placing biomes. + */ +public class BiomeQuirkExtent extends AbstractDelegateExtent { + + /** + * Create a new instance. + * + * @param extent the extent + */ + public BiomeQuirkExtent(Extent extent) { + super(extent); + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + boolean success = false; + if (!fullySupports3DBiomes()) { + // Also place at Y = 0 for proper handling + success = super.setBiome(position.withY(0), biome); + } + return super.setBiome(position, biome) || success; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/world/BlockQuirkExtent.java b/src/main/java/com/sk89q/worldedit/extent/world/BlockQuirkExtent.java new file mode 100644 index 0000000..d4a2e1b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/world/BlockQuirkExtent.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.world; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Handles various quirks when setting blocks, such as ice turning + * into water or containers dropping their contents. + * + * @deprecated Handled by the world entirely now + */ +@Deprecated +public class BlockQuirkExtent extends AbstractDelegateExtent { + + private final World world; + + /** + * Create a new instance. + * + * @param extent the extent + * @param world the world + */ + public BlockQuirkExtent(Extent extent, World world) { + super(extent); + checkNotNull(world); + this.world = world; + } + + @Override + public > boolean setBlock(BlockVector3 position, B block) throws WorldEditException { + BlockType existing = getExtent().getBlock(position).getBlockType(); + + if (existing.getMaterial().hasContainer()) { + world.clearContainerBlockContents(position); // Clear the container block so that it doesn't drop items + } else if (existing == BlockTypes.ICE) { + world.setBlock(position, BlockTypes.AIR.getDefaultState()); // Ice turns until water so this has to be done first + } + + return super.setBlock(position, block); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java b/src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java new file mode 100644 index 0000000..78a29bc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java @@ -0,0 +1,79 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.world; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Automatically loads chunks when blocks are accessed. + */ +public class ChunkLoadingExtent extends AbstractDelegateExtent { + + private final World world; + private final boolean enabled; + + /** + * Create a new instance. + * + * @param extent the extent + * @param world the world + * @param enabled true to enable + */ + public ChunkLoadingExtent(Extent extent, World world, boolean enabled) { + super(extent); + checkNotNull(world); + this.enabled = enabled; + this.world = world; + } + + /** + * Create a new instance with chunk loading enabled. + * + * @param extent the extent + * @param world the world + */ + public ChunkLoadingExtent(Extent extent, World world) { + this(extent, world, true); + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + if (enabled) { + world.checkLoadedChunk(location); + } + return super.setBlock(location, block); + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + if (enabled) { + world.checkLoadedChunk(position); + } + return super.setBiome(position, biome); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/world/SideEffectExtent.java b/src/main/java/com/sk89q/worldedit/extent/world/SideEffectExtent.java new file mode 100644 index 0000000..2c6c4cd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/world/SideEffectExtent.java @@ -0,0 +1,127 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.world; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.collection.BlockMap; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An extent that sets blocks in the world, with a {@link SideEffectSet}. + */ +public class SideEffectExtent extends AbstractDelegateExtent { + + private final World world; + private final Map positions = BlockMap.create(); + private final Set dirtyChunks = new HashSet<>(); + private SideEffectSet sideEffectSet = SideEffectSet.defaults(); + private boolean postEditSimulation; + + /** + * Create a new instance. + * + * @param world the world + */ + public SideEffectExtent(World world) { + super(world); + checkNotNull(world); + this.world = world; + } + + public boolean isPostEditSimulationEnabled() { + return postEditSimulation; + } + + public void setPostEditSimulationEnabled(boolean enabled) { + this.postEditSimulation = enabled; + } + + public SideEffectSet getSideEffectSet() { + return this.sideEffectSet; + } + + public void setSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + if (sideEffectSet.getState(SideEffect.LIGHTING) == SideEffect.State.DELAYED) { + dirtyChunks.add(BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4)); + } + if (postEditSimulation) { + positions.put(location, world.getBlock(location)); + } + + return world.setBlock(location, block, postEditSimulation ? SideEffectSet.none() : sideEffectSet); + } + + public boolean commitRequired() { + return postEditSimulation || !dirtyChunks.isEmpty(); + } + + @Override + protected Operation commitBefore() { + if (!commitRequired()) { + return null; + } + return new Operation() { + @Override + public Operation resume(RunContext run) throws WorldEditException { + if (!dirtyChunks.isEmpty()) { + world.fixAfterFastMode(dirtyChunks); + } + + if (postEditSimulation) { + Iterator> positionIterator = positions.entrySet().iterator(); + while (run.shouldContinue() && positionIterator.hasNext()) { + Map.Entry position = positionIterator.next(); + world.applySideEffects(position.getKey(), position.getValue(), sideEffectSet); + positionIterator.remove(); + } + + return !positions.isEmpty() ? this : null; + } + + return null; + } + + @Override + public void cancel() { + } + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java b/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java new file mode 100644 index 0000000..2cb6b02 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java @@ -0,0 +1,105 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.world; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Makes changes to the world as if a player had done so during survival mode. + * + *

Note that this extent may choose to not call the underlying + * extent and may instead call methods on the {@link World} that is passed + * in the constructor. For that reason, if you wish to "catch" changes, you + * should catch them before the changes reach this extent.

+ */ +public class SurvivalModeExtent extends AbstractDelegateExtent { + + private final World world; + private boolean toolUse = false; + private boolean stripNbt = false; + + /** + * Create a new instance. + * + * @param extent the extent + * @param world the world + */ + public SurvivalModeExtent(Extent extent, World world) { + super(extent); + checkNotNull(world); + this.world = world; + } + + /** + * Return whether changes to the world should be simulated with the + * use of game tools (such as pickaxes) whenever possible and reasonable. + * + *

For example, we could pretend that the act of setting a coal ore block + * to air (nothing) was the act of a player mining that coal ore block + * with a pickaxe, which would mean that a coal item would be dropped.

+ * + * @return true if tool use is to be simulated + */ + public boolean hasToolUse() { + return toolUse; + } + + /** + * Set whether changes to the world should be simulated with the + * use of game tools (such as pickaxes) whenever possible and reasonable. + * + * @param toolUse true if tool use is to be simulated + * @see #hasToolUse() for an explanation + */ + public void setToolUse(boolean toolUse) { + this.toolUse = toolUse; + } + + public boolean hasStripNbt() { + return stripNbt; + } + + public void setStripNbt(boolean stripNbt) { + this.stripNbt = stripNbt; + } + + @Override + public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { + if (toolUse && block.getBlockType().getMaterial().isAir()) { + world.simulateBlockMine(location); + return true; + } else { + // Can't be an inlined check due to inconsistent generic return type + if (stripNbt) { + return super.setBlock(location, block.toBaseBlock(null)); + } else { + return super.setBlock(location, block); + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java b/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java new file mode 100644 index 0000000..3636b9b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java @@ -0,0 +1,128 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.extent.world; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; +import java.util.List; + +/** + * Extent that ticks the watchdog before every world-affecting action. + */ +public class WatchdogTickingExtent extends AbstractDelegateExtent { + + // Number of operations we run per tick to the watchdog + private static final int OPS_PER_TICK = 100; + + private final Watchdog watchdog; + private boolean enabled; + private int ops; + + /** + * Create a new instance. + * + * @param extent the extent + * @param watchdog the watchdog to reset + */ + public WatchdogTickingExtent(Extent extent, Watchdog watchdog) { + super(extent); + this.watchdog = watchdog; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + private void onOperation() { + if (enabled) { + ops++; + if (ops == OPS_PER_TICK) { + watchdog.tick(); + ops = 0; + } + } + } + + @Override + public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { + onOperation(); + return super.setBlock(location, block); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + onOperation(); + return super.createEntity(location, entity); + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + onOperation(); + return super.setBiome(position, biome); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + onOperation(); + return super.getBlock(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + onOperation(); + return super.getFullBlock(position); + } + + @Override + public BiomeType getBiome(BlockVector3 position) { + onOperation(); + return super.getBiome(position); + } + + @Override + public List getEntities() { + onOperation(); + return super.getEntities(); + } + + @Override + public List getEntities(Region region) { + onOperation(); + return super.getEntities(region); + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java b/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java new file mode 100644 index 0000000..0886606 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java @@ -0,0 +1,117 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.google.common.collect.ImmutableList; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.context.StringRange; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestion; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.util.Substring; +import net.minecraft.commands.CommandSourceStack; +import org.enginehub.piston.inject.InjectedValueStore; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.inject.MapBackedValueStore; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; + +import static net.minecraft.commands.Commands.argument; +import static net.minecraft.commands.Commands.literal; + +public final class CommandWrapper { + private CommandWrapper() { + } + + public static void register(CommandDispatcher dispatcher, org.enginehub.piston.Command command) { + ImmutableList.Builder aliases = ImmutableList.builder(); + aliases.add(command.getName()).addAll(command.getAliases()); + for (String alias : aliases.build()) { + LiteralArgumentBuilder base = literal(alias).executes(FAKE_COMMAND) + .then(argument("args", StringArgumentType.greedyString()) + .suggests(CommandWrapper::suggest) + .executes(FAKE_COMMAND)); + if (command.getCondition() != org.enginehub.piston.Command.Condition.TRUE) { + base.requires(requirementsFor(command)); + } + dispatcher.register(base); + } + } + + public static final Command FAKE_COMMAND = ctx -> { + if (ctx.getSource().getLevel().isClientSide) { + return 0; + } + return 1; + }; + + private static Predicate requirementsFor(org.enginehub.piston.Command mapping) { + return ctx -> { + final Actor actor = ForgeAdapter.adaptCommandSource(ctx); + InjectedValueStore store = MapBackedValueStore.create(); + store.injectValue(Key.of(Actor.class), context -> Optional.of(actor)); + return mapping.getCondition().satisfied(store); + }; + } + + private static CompletableFuture suggest(CommandContext context, + SuggestionsBuilder builder) throws CommandSyntaxException { + CommandSuggestionEvent event = new CommandSuggestionEvent( + ForgeAdapter.adaptCommandSource(context.getSource()), + builder.getInput() + ); + WorldEdit.getInstance().getEventBus().post(event); + List suggestions = event.getSuggestions(); + + ImmutableList.Builder result = ImmutableList.builder(); + + for (Substring suggestion : suggestions) { + String suggestionText = suggestion.getSubstring(); + // If at end, we are actually suggesting the next argument + // Ensure there is a space! + if (suggestion.getStart() == suggestion.getEnd() + && suggestion.getEnd() == builder.getInput().length() + && !builder.getInput().endsWith(" ") + && !builder.getInput().endsWith("\"")) { + suggestionText = " " + suggestionText; + } + result.add(new Suggestion( + StringRange.between(suggestion.getStart(), suggestion.getEnd()), + suggestionText + )); + } + + return CompletableFuture.completedFuture( + Suggestions.create(builder.getInput(), result.build()) + ); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java new file mode 100644 index 0000000..f8f922d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -0,0 +1,267 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.forge.internal.ForgeTransmogrifier; +import com.sk89q.worldedit.forge.internal.NBTConverter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BaseCommandBlock; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.server.ServerLifecycleHooks; + +import java.util.Comparator; +import java.util.Map; +import java.util.Objects; +import java.util.TreeMap; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class ForgeAdapter { + + private ForgeAdapter() { + } + + public static World adapt(ServerLevel world) { + return new ForgeWorld(world); + } + + /** + * Create a Forge world from a WorldEdit world. + * + * @param world the WorldEdit world + * @return a Forge world + */ + public static ServerLevel adapt(World world) { + checkNotNull(world); + if (world instanceof ForgeWorld) { + return ((ForgeWorld) world).getWorld(); + } else { + // TODO introduce a better cross-platform world API to match more easily + throw new UnsupportedOperationException("Cannot adapt from a " + world.getClass()); + } + } + + public static Biome adapt(BiomeType biomeType) { + return ServerLifecycleHooks.getCurrentServer() + .registryAccess() + .registryOrThrow(Registries.BIOME) + .getOptional(new ResourceLocation(biomeType.getId())) + .orElseThrow(() -> new IllegalStateException("No biome for " + biomeType.getId())); + } + + public static BiomeType adapt(Biome biome) { + ResourceLocation id = ServerLifecycleHooks.getCurrentServer() + .registryAccess() + .registryOrThrow(Registries.BIOME) + .getKey(biome); + Objects.requireNonNull(id, "biome is not registered"); + return BiomeTypes.get(id.toString()); + } + + public static Vector3 adapt(Vec3 vector) { + return Vector3.at(vector.x, vector.y, vector.z); + } + + public static BlockVector3 adapt(BlockPos pos) { + return BlockVector3.at(pos.getX(), pos.getY(), pos.getZ()); + } + + public static Vec3 toVec3(BlockVector3 vector) { + return new Vec3(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); + } + + public static net.minecraft.core.Direction adapt(Direction face) { + switch (face) { + case NORTH: return net.minecraft.core.Direction.NORTH; + case SOUTH: return net.minecraft.core.Direction.SOUTH; + case WEST: return net.minecraft.core.Direction.WEST; + case EAST: return net.minecraft.core.Direction.EAST; + case DOWN: return net.minecraft.core.Direction.DOWN; + case UP: + default: + return net.minecraft.core.Direction.UP; + } + } + + public static Direction adaptEnumFacing(@Nullable net.minecraft.core.Direction face) { + if (face == null) { + return null; + } + switch (face) { + case NORTH: return Direction.NORTH; + case SOUTH: return Direction.SOUTH; + case WEST: return Direction.WEST; + case EAST: return Direction.EAST; + case DOWN: return Direction.DOWN; + case UP: + default: + return Direction.UP; + } + } + + public static BlockPos toBlockPos(BlockVector3 vector) { + return new BlockPos(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); + } + + /** + * Adapts property. + * @deprecated without replacement, use the block adapter methods + */ + @Deprecated + public static Property adaptProperty(net.minecraft.world.level.block.state.properties.Property property) { + return ForgeTransmogrifier.transmogToWorldEditProperty(property); + } + + /** + * Adapts properties. + * @deprecated without replacement, use the block adapter methods + */ + @Deprecated + public static Map, Object> adaptProperties(BlockType block, Map, Comparable> mcProps) { + Map, Object> props = new TreeMap<>(Comparator.comparing(Property::getName)); + for (Map.Entry, Comparable> prop : mcProps.entrySet()) { + Object value = prop.getValue(); + if (prop.getKey() instanceof DirectionProperty) { + value = adaptEnumFacing((net.minecraft.core.Direction) value); + } else if (prop.getKey() instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + value = ((StringRepresentable) value).getSerializedName(); + } + props.put(block.getProperty(prop.getKey().getName()), value); + } + return props; + } + + public static net.minecraft.world.level.block.state.BlockState adapt(BlockState blockState) { + int blockStateId = BlockStateIdAccess.getBlockStateId(blockState); + if (!BlockStateIdAccess.isValidInternalId(blockStateId)) { + return ForgeTransmogrifier.transmogToMinecraft(blockState); + } + return Block.stateById(blockStateId); + } + + public static BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { + int blockStateId = Block.getId(blockState); + BlockState worldEdit = BlockStateIdAccess.getBlockStateById(blockStateId); + if (worldEdit == null) { + return ForgeTransmogrifier.transmogToWorldEdit(blockState); + } + return worldEdit; + } + + public static Block adapt(BlockType blockType) { + return BuiltInRegistries.BLOCK.get(new ResourceLocation(blockType.getId())); + } + + public static BlockType adapt(Block block) { + return BlockTypes.get(BuiltInRegistries.BLOCK.getKey(block).toString()); + } + + public static Item adapt(ItemType itemType) { + return BuiltInRegistries.ITEM.get(new ResourceLocation(itemType.getId())); + } + + public static ItemType adapt(Item item) { + return ItemTypes.get(BuiltInRegistries.ITEM.getKey(item).toString()); + } + + public static ItemStack adapt(BaseItemStack baseItemStack) { + net.minecraft.nbt.CompoundTag forgeCompound = null; + if (baseItemStack.getNbtData() != null) { + forgeCompound = NBTConverter.toNative(baseItemStack.getNbtData()); + } + final ItemStack itemStack = new ItemStack(adapt(baseItemStack.getType()), baseItemStack.getAmount()); + itemStack.setTag(forgeCompound); + return itemStack; + } + + public static BaseItemStack adapt(ItemStack itemStack) { + CompoundTag tag = NBTConverter.fromNative(itemStack.save(new net.minecraft.nbt.CompoundTag())); + if (tag.getValue().isEmpty()) { + tag = null; + } else { + final Tag tagTag = tag.getValue().get("tag"); + if (tagTag instanceof CompoundTag) { + tag = ((CompoundTag) tagTag); + } else { + tag = null; + } + } + return new BaseItemStack(adapt(itemStack.getItem()), tag, itemStack.getCount()); + } + + /** + * Get the WorldEdit proxy for the given player. + * + * @param player the player + * @return the WorldEdit player + */ + public static ForgePlayer adaptPlayer(ServerPlayer player) { + checkNotNull(player); + return new ForgePlayer(player); + } + + /** + * Get the WorldEdit proxy for the given command source. + * + * @param commandSourceStack the command source + * @return the WorldEdit actor + */ + public static Actor adaptCommandSource(CommandSourceStack commandSourceStack) { + checkNotNull(commandSourceStack); + if (commandSourceStack.isPlayer()) { + return adaptPlayer(commandSourceStack.getPlayer()); + } + if (ForgeWorldEdit.inst.getConfig().commandBlockSupport && commandSourceStack.source instanceof BaseCommandBlock commandBlock) { + return new ForgeBlockCommandSender(commandBlock); + } + + return new ForgeCommandSender(commandSourceStack); + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java b/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java new file mode 100644 index 0000000..efa7117 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeBiomeRegistry.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import net.kyori.text.Component; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.biome.BiomeData; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import net.minecraft.Util; +import net.minecraft.resources.ResourceLocation; + +/** + * Provides access to biome data in Forge. + */ +class ForgeBiomeRegistry implements BiomeRegistry { + + @Override + public Component getRichName(BiomeType biomeType) { + return TranslatableComponent.of(Util.makeDescriptionId("biome", new ResourceLocation(biomeType.getId()))); + } + + @Deprecated + @Override + public BiomeData getData(BiomeType biome) { + return new ForgeBiomeData(biome); + } + + /** + * Cached biome data information. + */ + @Deprecated + private static class ForgeBiomeData implements BiomeData { + private final BiomeType biome; + + /** + * Create a new instance. + * + * @param biome the base biome + */ + private ForgeBiomeData(BiomeType biome) { + this.biome = biome; + } + + @SuppressWarnings("deprecation") + @Override + public String getName() { + return biome.getId(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java b/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java new file mode 100644 index 0000000..0e60e8a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Streams; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.block.Block; + +import java.util.Set; + +public class ForgeBlockCategoryRegistry implements BlockCategoryRegistry { + @Override + public Set getCategorisedByName(String category) { + Iterable> tagged = BuiltInRegistries.BLOCK.getTagOrEmpty(TagKey.create(Registries.BLOCK, new ResourceLocation(category))); + + return Streams.stream(tagged) + .map(Holder::value) + .map(ForgeAdapter::adapt) + .collect(ImmutableSet.toImmutableSet()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCommandSender.java b/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCommandSender.java new file mode 100644 index 0000000..0ef0dd5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCommandSender.java @@ -0,0 +1,179 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.AbstractCommandBlockActor; +import com.sk89q.worldedit.session.SessionKey; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.util.formatting.WorldEditText; +import net.kyori.text.Component; +import net.kyori.text.serializer.gson.GsonComponentSerializer; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.BaseCommandBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.neoforged.fml.LogicalSide; +import net.neoforged.neoforge.common.util.LogicalSidedProvider; + +import java.nio.charset.StandardCharsets; +import java.util.Locale; +import java.util.UUID; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ForgeBlockCommandSender extends AbstractCommandBlockActor { + private final BaseCommandBlock sender; + private final UUID uuid; + + public ForgeBlockCommandSender(BaseCommandBlock sender) { + super(new Location(ForgeAdapter.adapt(checkNotNull(sender).getLevel()), ForgeAdapter.adapt(sender.getPosition()))); + + this.sender = sender; + this.uuid = UUID.nameUUIDFromBytes((UUID_PREFIX + sender.getName()).getBytes(StandardCharsets.UTF_8)); + } + + @Override + public String getName() { + return sender.getName().getString(); + } + + @Override + @Deprecated + public void printRaw(String msg) { + for (String part : msg.split("\n")) { + sendMessage(net.minecraft.network.chat.Component.literal(part)); + } + } + + @Override + @Deprecated + public void printDebug(String msg) { + sendColorized(msg, ChatFormatting.GRAY); + } + + @Override + @Deprecated + public void print(String msg) { + sendColorized(msg, ChatFormatting.LIGHT_PURPLE); + } + + @Override + @Deprecated + public void printError(String msg) { + sendColorized(msg, ChatFormatting.RED); + } + + @Override + public void print(Component component) { + sendMessage(net.minecraft.network.chat.Component.Serializer.fromJson( + GsonComponentSerializer.INSTANCE.serialize(WorldEditText.format(component, getLocale())) + )); + } + + private void sendColorized(String msg, ChatFormatting formatting) { + for (String part : msg.split("\n")) { + var component = net.minecraft.network.chat.Component.literal(part); + component.withStyle(formatting); + sendMessage(component); + } + } + + private void sendMessage(net.minecraft.network.chat.Component textComponent) { + this.sender.sendSystemMessage(textComponent); + } + + @Override + public Locale getLocale() { + return WorldEdit.getInstance().getConfiguration().defaultLocale; + } + + @Override + public UUID getUniqueId() { + return uuid; + } + + @Override + public String[] getGroups() { + return new String[0]; + } + + @Override + public void checkPermission(String permission) throws AuthorizationException { + if (!hasPermission(permission)) { + throw new AuthorizationException(); + } + } + + @Override + public boolean hasPermission(String permission) { + return true; + } + + public BaseCommandBlock getSender() { + return this.sender; + } + + @Override + public SessionKey getSessionKey() { + return new SessionKey() { + + private volatile boolean active = true; + + private void updateActive() { + BlockPos pos = new BlockPos((int) sender.getPosition().x, (int) sender.getPosition().y, (int) sender.getPosition().z); + int chunkX = SectionPos.blockToSectionCoord(pos.getX()); + int chunkZ = SectionPos.blockToSectionCoord(pos.getZ()); + if (!sender.getLevel().getChunkSource().hasChunk(chunkX, chunkZ)) { + active = false; + return; + } + Block type = sender.getLevel().getBlockState(pos).getBlock(); + active = type == Blocks.COMMAND_BLOCK + || type == Blocks.CHAIN_COMMAND_BLOCK + || type == Blocks.REPEATING_COMMAND_BLOCK; + } + + @Override + public String getName() { + return sender.getName().getString(); + } + + @Override + public boolean isActive() { + LogicalSidedProvider.WORKQUEUE.get(LogicalSide.SERVER).submitAsync(this::updateActive); + return active; + } + + @Override + public boolean isPersistent() { + return true; + } + + @Override + public UUID getUniqueId() { + return uuid; + } + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java b/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java new file mode 100644 index 0000000..7fa78ca --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java @@ -0,0 +1,96 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.world.registry.BlockMaterial; +import com.sk89q.worldedit.world.registry.PassthroughBlockMaterial; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.PushReaction; + +import javax.annotation.Nullable; + +/** + * Forge block material that pulls as much info as possible from the Minecraft + * Material, and passes the rest to another implementation, typically the + * bundled block info. + */ +public class ForgeBlockMaterial extends PassthroughBlockMaterial { + + private final BlockState block; + + public ForgeBlockMaterial(BlockState block, @Nullable BlockMaterial secondary) { + super(secondary); + this.block = block; + } + + @Override + public boolean isAir() { + return block.isAir() || super.isAir(); + } + + @Override + public boolean isOpaque() { + return block.canOcclude(); + } + + @SuppressWarnings("deprecation") + @Override + public boolean isLiquid() { + return block.liquid(); + } + + @SuppressWarnings("deprecation") + @Override + public boolean isSolid() { + return block.isSolid(); + } + + @Override + public boolean isFragileWhenPushed() { + return block.getPistonPushReaction() == PushReaction.DESTROY; + } + + @Override + public boolean isUnpushable() { + return block.getPistonPushReaction() == PushReaction.BLOCK; + } + + @SuppressWarnings("deprecation") + @Override + public boolean isMovementBlocker() { + return block.blocksMotion(); + } + + @Override + public boolean isBurnable() { + return block.ignitedByLava(); + } + + @Override + public boolean isToolRequired() { + return !block.requiresCorrectToolForDrops(); + } + + @Override + public boolean isReplacedDuringPlacement() { + return block.canBeReplaced(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java b/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java new file mode 100644 index 0000000..0cdc9f8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java @@ -0,0 +1,77 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.forge.internal.ForgeTransmogrifier; +import com.sk89q.worldedit.registry.state.Property; +import net.kyori.text.Component; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import com.sk89q.worldedit.world.registry.BundledBlockRegistry; +import net.minecraft.world.level.block.Block; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.OptionalInt; +import java.util.TreeMap; + +public class ForgeBlockRegistry extends BundledBlockRegistry { + + private final Map materialMap = new HashMap<>(); + + @Override + public Component getRichName(BlockType blockType) { + return TranslatableComponent.of(ForgeAdapter.adapt(blockType).getDescriptionId()); + } + + @Override + public BlockMaterial getMaterial(BlockType blockType) { + Block block = ForgeAdapter.adapt(blockType); + if (block == null) { + return super.getMaterial(blockType); + } + return materialMap.computeIfAbsent( + block.defaultBlockState(), + s -> new ForgeBlockMaterial(s, super.getMaterial(blockType)) + ); + } + + @Override + public Map> getProperties(BlockType blockType) { + Block block = ForgeAdapter.adapt(blockType); + Map> map = new TreeMap<>(); + Collection> propertyKeys = block + .defaultBlockState() + .getProperties(); + for (net.minecraft.world.level.block.state.properties.Property key : propertyKeys) { + map.put(key.getName(), ForgeTransmogrifier.transmogToWorldEditProperty(key)); + } + return map; + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + net.minecraft.world.level.block.state.BlockState equivalent = ForgeAdapter.adapt(state); + return OptionalInt.of(Block.getId(equivalent)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeCommandSender.java b/src/main/java/com/sk89q/worldedit/forge/ForgeCommandSender.java new file mode 100644 index 0000000..6689e82 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeCommandSender.java @@ -0,0 +1,157 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.AbstractNonPlayerActor; +import com.sk89q.worldedit.session.SessionKey; +import com.sk89q.worldedit.util.formatting.WorldEditText; +import net.kyori.text.Component; +import net.kyori.text.serializer.gson.GsonComponentSerializer; +import net.minecraft.ChatFormatting; +import net.minecraft.commands.CommandSourceStack; + +import java.util.Locale; +import java.util.UUID; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +public class ForgeCommandSender extends AbstractNonPlayerActor { + + /** + * One time generated ID. + */ + private static final UUID DEFAULT_ID = UUID.fromString("a233eb4b-4cab-42cd-9fd9-7e7b9a3f74be"); + + private final CommandSourceStack sender; + + public ForgeCommandSender(CommandSourceStack sender) { + checkNotNull(sender); + checkArgument(!sender.isPlayer(), "Cannot wrap a player"); + + this.sender = sender; + } + + @Override + public UUID getUniqueId() { + return DEFAULT_ID; + } + + @Override + public String getName() { + return sender.getTextName(); + } + + @Override + @Deprecated + public void printRaw(String msg) { + for (String part : msg.split("\n")) { + sendMessage(net.minecraft.network.chat.Component.literal(part)); + } + } + + @Override + @Deprecated + public void printDebug(String msg) { + sendColorized(msg, ChatFormatting.GRAY); + } + + @Override + @Deprecated + public void print(String msg) { + sendColorized(msg, ChatFormatting.LIGHT_PURPLE); + } + + @Override + @Deprecated + public void printError(String msg) { + sendColorized(msg, ChatFormatting.RED); + } + + @Override + public void print(Component component) { + sendMessage(net.minecraft.network.chat.Component.Serializer.fromJson( + GsonComponentSerializer.INSTANCE.serialize(WorldEditText.format(component, getLocale())) + )); + } + + private void sendColorized(String msg, ChatFormatting formatting) { + for (String part : msg.split("\n")) { + var component = net.minecraft.network.chat.Component.literal(part); + component.withStyle(formatting); + sendMessage(component); + } + } + + private void sendMessage(net.minecraft.network.chat.Component textComponent) { + this.sender.sendSystemMessage(textComponent); + } + + @Override + public String[] getGroups() { + return new String[0]; + } + + @Override + public boolean hasPermission(String perm) { + return true; + } + + @Override + public void checkPermission(String permission) { + } + + @Override + public Locale getLocale() { + return WorldEdit.getInstance().getConfiguration().defaultLocale; + } + + public CommandSourceStack getSender() { + return this.sender; + } + + @Override + public SessionKey getSessionKey() { + return new SessionKey() { + @Nullable + @Override + public String getName() { + return sender.getTextName(); + } + + @Override + public boolean isActive() { + return true; + } + + @Override + public boolean isPersistent() { + return true; + } + + @Override + public UUID getUniqueId() { + return DEFAULT_ID; + } + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeConfiguration.java b/src/main/java/com/sk89q/worldedit/forge/ForgeConfiguration.java new file mode 100644 index 0000000..a20070d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeConfiguration.java @@ -0,0 +1,46 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.util.PropertiesConfiguration; + +import java.io.File; +import java.nio.file.Path; + +public class ForgeConfiguration extends PropertiesConfiguration { + + public boolean creativeEnable = false; + public boolean cheatMode = false; + + public ForgeConfiguration(ForgeWorldEdit mod) { + super(mod.getWorkingDir().resolve("worldedit.properties")); + } + + @Override + protected void loadExtra() { + creativeEnable = getBool("use-in-creative", false); + cheatMode = getBool("cheat-mode", false); + } + + @Override + public Path getWorkingDirectoryPath() { + return ForgeWorldEdit.inst.getWorkingDir(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java b/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java new file mode 100644 index 0000000..bd90573 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java @@ -0,0 +1,2776 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DSL.TypeReference; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.DataFixerBuilder; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.forge.internal.NBTConverter; +import net.minecraft.core.Direction; +import net.minecraft.nbt.FloatTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.util.StringUtil; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.item.DyeColor; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Executor; +import java.util.stream.Collectors; +import javax.annotation.Nullable; + +/** + * Handles converting all Pre 1.13.2 data using the Legacy DataFix System (ported to 1.13.2) + * + *

+ * We register a DFU Fixer per Legacy Data Version and apply the fixes using legacy strategy + * which is safer, faster and cleaner code. + *

+ * + *

+ * The pre DFU code did not fail when the Source version was unknown. + *

+ * + *

+ * This class also provides util methods for converting compounds to wrap the update call to + * receive the source version in the compound. + *

+ */ +@SuppressWarnings({ "UnnecessarilyQualifiedStaticUsage", "unchecked", "rawtypes" }) +class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { + + @SuppressWarnings("unchecked") + @Override + public T fixUp(FixType type, T original, int srcVer) { + if (type == FixTypes.CHUNK) { + return (T) fixChunk((CompoundTag) original, srcVer); + } else if (type == FixTypes.BLOCK_ENTITY) { + return (T) fixBlockEntity((CompoundTag) original, srcVer); + } else if (type == FixTypes.ENTITY) { + return (T) fixEntity((CompoundTag) original, srcVer); + } else if (type == FixTypes.BLOCK_STATE) { + return (T) fixBlockState((String) original, srcVer); + } else if (type == FixTypes.ITEM_TYPE) { + return (T) fixItemType((String) original, srcVer); + } else if (type == FixTypes.BIOME) { + return (T) fixBiome((String) original, srcVer); + } + return original; + } + + private CompoundTag fixChunk(CompoundTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = NBTConverter.toNative(originalChunk); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private CompoundTag fixBlockEntity(CompoundTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = NBTConverter.toNative(origTileEnt); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private CompoundTag fixEntity(CompoundTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = NBTConverter.toNative(origEnt); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private String fixBlockState(String blockState, int srcVer) { + net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); + Dynamic dynamic = new Dynamic<>(OPS_NBT, stateNBT); + net.minecraft.nbt.CompoundTag fixed = (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(References.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); + return nbtToState(fixed); + } + + private String nbtToState(net.minecraft.nbt.CompoundTag tagCompound) { + StringBuilder sb = new StringBuilder(); + sb.append(tagCompound.getString("Name")); + if (tagCompound.contains("Properties", 10)) { + sb.append('['); + net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); + sb.append(props.getAllKeys().stream().map(k -> k + "=" + props.getString(k).replace("\"", "")).collect(Collectors.joining(","))); + sb.append(']'); + } + return sb.toString(); + } + + private static net.minecraft.nbt.CompoundTag stateToNBT(String blockState) { + int propIdx = blockState.indexOf('['); + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + if (propIdx < 0) { + tag.putString("Name", blockState); + } else { + tag.putString("Name", blockState.substring(0, propIdx)); + net.minecraft.nbt.CompoundTag propTag = new net.minecraft.nbt.CompoundTag(); + String props = blockState.substring(propIdx + 1, blockState.length() - 1); + String[] propArr = props.split(","); + for (String pair : propArr) { + final String[] split = pair.split("="); + propTag.putString(split[0], split[1]); + } + tag.put("Properties", propTag); + } + return tag; + } + + private String fixBiome(String key, int srcVer) { + return fixName(key, srcVer, References.BIOME); + } + + private String fixItemType(String key, int srcVer) { + return fixName(key, srcVer, References.ITEM_NAME); + } + + private static String fixName(String key, int srcVer, TypeReference type) { + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, StringTag.valueOf(key)), srcVer, DATA_VERSION) + .asString().result().orElse(key); + } + + private static final NbtOps OPS_NBT = NbtOps.INSTANCE; + private static final int LEGACY_VERSION = 1343; + private static int DATA_VERSION; + private static ForgeDataFixer INSTANCE; + + private final Map> converters = new EnumMap<>(LegacyType.class); + private final Map> inspectors = new EnumMap<>(LegacyType.class); + + // Set on build + private final DataFixer fixer; + private static final Map DFU_TO_LEGACY = new HashMap<>(); + + public enum LegacyType { + LEVEL(References.LEVEL), + PLAYER(References.PLAYER), + CHUNK(References.CHUNK), + BLOCK_ENTITY(References.BLOCK_ENTITY), + ENTITY(References.ENTITY), + ITEM_INSTANCE(References.ITEM_STACK), + OPTIONS(References.OPTIONS), + STRUCTURE(References.STRUCTURE); + + private final TypeReference type; + + LegacyType(TypeReference type) { + this.type = type; + DFU_TO_LEGACY.put(type.typeName(), this); + } + + public TypeReference getDFUType() { + return type; + } + } + + ForgeDataFixer(int dataVersion) { + super(dataVersion); + DATA_VERSION = dataVersion; + INSTANCE = this; + registerConverters(); + registerInspectors(); + this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); + } + + @Override + public DataFixer buildUnoptimized() { + return fixer; + } + + @Override + public DataFixer buildOptimized(final Set requiredTypes, final Executor executor) { + return fixer; + } + + private class WrappedDataFixer implements DataFixer { + private final DataFixer realFixer; + + WrappedDataFixer(DataFixer realFixer) { + this.realFixer = realFixer; + } + + @Override + public Dynamic update(TypeReference type, Dynamic dynamic, int sourceVer, int targetVer) { + LegacyType legacyType = DFU_TO_LEGACY.get(type.typeName()); + if (sourceVer < LEGACY_VERSION && legacyType != null) { + net.minecraft.nbt.CompoundTag cmp = (net.minecraft.nbt.CompoundTag) dynamic.getValue(); + int desiredVersion = Math.min(targetVer, LEGACY_VERSION); + + cmp = convert(legacyType, cmp, sourceVer, desiredVersion); + sourceVer = desiredVersion; + dynamic = new Dynamic(OPS_NBT, cmp); + } + return realFixer.update(type, dynamic, sourceVer, targetVer); + } + + private net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int desiredVersion) { + List converters = ForgeDataFixer.this.converters.get(type); + if (converters != null && !converters.isEmpty()) { + for (DataConverter converter : converters) { + int dataVersion = converter.getDataVersion(); + if (dataVersion > sourceVer && dataVersion <= desiredVersion) { + cmp = converter.convert(cmp); + } + } + } + + List inspectors = ForgeDataFixer.this.inspectors.get(type); + if (inspectors != null && !inspectors.isEmpty()) { + for (DataInspector inspector : inspectors) { + cmp = inspector.inspect(cmp, sourceVer, desiredVersion); + } + } + + return cmp; + } + + @Override + public Schema getSchema(int i) { + return realFixer.getSchema(i); + } + } + + public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp) { + return convert(type.getDFUType(), cmp); + } + + public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer) { + return convert(type.getDFUType(), cmp, sourceVer); + } + + public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + return convert(type.getDFUType(), cmp, sourceVer, targetVer); + } + + public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp) { + int i = cmp.contains("DataVersion", 99) ? cmp.getInt("DataVersion") : -1; + return convert(type, cmp, i); + } + + public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp, int sourceVer) { + return convert(type, cmp, sourceVer, DATA_VERSION); + } + + public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (sourceVer >= targetVer) { + return cmp; + } + return (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer).getValue(); + } + + + public interface DataInspector { + net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer); + } + + public interface DataConverter { + + int getDataVersion(); + + net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp); + } + + + private void registerInspector(LegacyType type, DataInspector inspector) { + this.inspectors.computeIfAbsent(type, k -> new ArrayList<>()).add(inspector); + } + + private void registerConverter(LegacyType type, DataConverter converter) { + int version = converter.getDataVersion(); + + List list = this.converters.computeIfAbsent(type, k -> new ArrayList<>()); + if (!list.isEmpty() && list.get(list.size() - 1).getDataVersion() > version) { + for (int j = 0; j < list.size(); ++j) { + if (list.get(j).getDataVersion() > version) { + list.add(j, converter); + break; + } + } + } else { + list.add(converter); + } + } + + private void registerInspectors() { + registerEntityItemList("EntityHorseDonkey", "SaddleItem", "Items"); + registerEntityItemList("EntityHorseMule", "Items"); + registerEntityItemList("EntityMinecartChest", "Items"); + registerEntityItemList("EntityMinecartHopper", "Items"); + registerEntityItemList("EntityVillager", "Inventory"); + registerEntityItemListEquipment("EntityArmorStand"); + registerEntityItemListEquipment("EntityBat"); + registerEntityItemListEquipment("EntityBlaze"); + registerEntityItemListEquipment("EntityCaveSpider"); + registerEntityItemListEquipment("EntityChicken"); + registerEntityItemListEquipment("EntityCow"); + registerEntityItemListEquipment("EntityCreeper"); + registerEntityItemListEquipment("EntityEnderDragon"); + registerEntityItemListEquipment("EntityEnderman"); + registerEntityItemListEquipment("EntityEndermite"); + registerEntityItemListEquipment("EntityEvoker"); + registerEntityItemListEquipment("EntityGhast"); + registerEntityItemListEquipment("EntityGiantZombie"); + registerEntityItemListEquipment("EntityGuardian"); + registerEntityItemListEquipment("EntityGuardianElder"); + registerEntityItemListEquipment("EntityHorse"); + registerEntityItemListEquipment("EntityHorseDonkey"); + registerEntityItemListEquipment("EntityHorseMule"); + registerEntityItemListEquipment("EntityHorseSkeleton"); + registerEntityItemListEquipment("EntityHorseZombie"); + registerEntityItemListEquipment("EntityIronGolem"); + registerEntityItemListEquipment("EntityMagmaCube"); + registerEntityItemListEquipment("EntityMushroomCow"); + registerEntityItemListEquipment("EntityOcelot"); + registerEntityItemListEquipment("EntityPig"); + registerEntityItemListEquipment("EntityPigZombie"); + registerEntityItemListEquipment("EntityRabbit"); + registerEntityItemListEquipment("EntitySheep"); + registerEntityItemListEquipment("EntityShulker"); + registerEntityItemListEquipment("EntitySilverfish"); + registerEntityItemListEquipment("EntitySkeleton"); + registerEntityItemListEquipment("EntitySkeletonStray"); + registerEntityItemListEquipment("EntitySkeletonWither"); + registerEntityItemListEquipment("EntitySlime"); + registerEntityItemListEquipment("EntitySnowman"); + registerEntityItemListEquipment("EntitySpider"); + registerEntityItemListEquipment("EntitySquid"); + registerEntityItemListEquipment("EntityVex"); + registerEntityItemListEquipment("EntityVillager"); + registerEntityItemListEquipment("EntityVindicator"); + registerEntityItemListEquipment("EntityWitch"); + registerEntityItemListEquipment("EntityWither"); + registerEntityItemListEquipment("EntityWolf"); + registerEntityItemListEquipment("EntityZombie"); + registerEntityItemListEquipment("EntityZombieHusk"); + registerEntityItemListEquipment("EntityZombieVillager"); + registerEntityItemSingle("EntityFireworks", "FireworksItem"); + registerEntityItemSingle("EntityHorse", "ArmorItem"); + registerEntityItemSingle("EntityHorse", "SaddleItem"); + registerEntityItemSingle("EntityHorseMule", "SaddleItem"); + registerEntityItemSingle("EntityHorseSkeleton", "SaddleItem"); + registerEntityItemSingle("EntityHorseZombie", "SaddleItem"); + registerEntityItemSingle("EntityItem", "Item"); + registerEntityItemSingle("EntityItemFrame", "Item"); + registerEntityItemSingle("EntityPotion", "Potion"); + + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItem("TileEntityRecordPlayer", "RecordItem")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityBrewingStand", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityChest", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityDispenser", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityDropper", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityFurnace", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityHopper", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityShulkerBox", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorMobSpawnerMobs()); + registerInspector(LegacyType.CHUNK, new DataInspectorChunks()); + registerInspector(LegacyType.ENTITY, new DataInspectorCommandBlock()); + registerInspector(LegacyType.ENTITY, new DataInspectorEntityPassengers()); + registerInspector(LegacyType.ENTITY, new DataInspectorMobSpawnerMinecart()); + registerInspector(LegacyType.ENTITY, new DataInspectorVillagers()); + registerInspector(LegacyType.ITEM_INSTANCE, new DataInspectorBlockEntity()); + registerInspector(LegacyType.ITEM_INSTANCE, new DataInspectorEntity()); + registerInspector(LegacyType.LEVEL, new DataInspectorLevelPlayer()); + registerInspector(LegacyType.PLAYER, new DataInspectorPlayer()); + registerInspector(LegacyType.PLAYER, new DataInspectorPlayerVehicle()); + registerInspector(LegacyType.STRUCTURE, new DataInspectorStructure()); + } + + private void registerConverters() { + registerConverter(LegacyType.ENTITY, new DataConverterEquipment()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterSignText()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterMaterialId()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterPotionId()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterSpawnEgg()); + registerConverter(LegacyType.ENTITY, new DataConverterMinecart()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterMobSpawner()); + registerConverter(LegacyType.ENTITY, new DataConverterUUID()); + registerConverter(LegacyType.ENTITY, new DataConverterHealth()); + registerConverter(LegacyType.ENTITY, new DataConverterSaddle()); + registerConverter(LegacyType.ENTITY, new DataConverterHanging()); + registerConverter(LegacyType.ENTITY, new DataConverterDropChances()); + registerConverter(LegacyType.ENTITY, new DataConverterRiding()); + registerConverter(LegacyType.ENTITY, new DataConverterArmorStand()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBook()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterCookedFish()); + registerConverter(LegacyType.ENTITY, new DataConverterZombie()); + registerConverter(LegacyType.OPTIONS, new DataConverterVBO()); + registerConverter(LegacyType.ENTITY, new DataConverterGuardian()); + registerConverter(LegacyType.ENTITY, new DataConverterSkeleton()); + registerConverter(LegacyType.ENTITY, new DataConverterZombieType()); + registerConverter(LegacyType.ENTITY, new DataConverterHorse()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterTileEntity()); + registerConverter(LegacyType.ENTITY, new DataConverterEntity()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBanner()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterPotionWater()); + registerConverter(LegacyType.ENTITY, new DataConverterShulker()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterShulkerBoxItem()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterShulkerBoxBlock()); + registerConverter(LegacyType.OPTIONS, new DataConverterLang()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterTotem()); + registerConverter(LegacyType.CHUNK, new DataConverterBedBlock()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBedItem()); + } + + private void registerEntityItemList(String type, String... keys) { + registerInspector(LegacyType.ENTITY, new DataInspectorItemList(type, keys)); + } + + private void registerEntityItemSingle(String type, String key) { + registerInspector(LegacyType.ENTITY, new DataInspectorItem(type, key)); + } + + private void registerEntityItemListEquipment(String type) { + registerEntityItemList(type, "ArmorItems", "HandItems"); + } + + private static final Map OLD_ID_TO_KEY_MAP = new HashMap<>(); + + static { + final Map map = OLD_ID_TO_KEY_MAP; + map.put("EntityItem", new ResourceLocation("item")); + map.put("EntityExperienceOrb", new ResourceLocation("xp_orb")); + map.put("EntityAreaEffectCloud", new ResourceLocation("area_effect_cloud")); + map.put("EntityGuardianElder", new ResourceLocation("elder_guardian")); + map.put("EntitySkeletonWither", new ResourceLocation("wither_skeleton")); + map.put("EntitySkeletonStray", new ResourceLocation("stray")); + map.put("EntityEgg", new ResourceLocation("egg")); + map.put("EntityLeash", new ResourceLocation("leash_knot")); + map.put("EntityPainting", new ResourceLocation("painting")); + map.put("EntityTippedArrow", new ResourceLocation("arrow")); + map.put("EntitySnowball", new ResourceLocation("snowball")); + map.put("EntityLargeFireball", new ResourceLocation("fireball")); + map.put("EntitySmallFireball", new ResourceLocation("small_fireball")); + map.put("EntityEnderPearl", new ResourceLocation("ender_pearl")); + map.put("EntityEnderSignal", new ResourceLocation("eye_of_ender_signal")); + map.put("EntityPotion", new ResourceLocation("potion")); + map.put("EntityThrownExpBottle", new ResourceLocation("xp_bottle")); + map.put("EntityItemFrame", new ResourceLocation("item_frame")); + map.put("EntityWitherSkull", new ResourceLocation("wither_skull")); + map.put("EntityTNTPrimed", new ResourceLocation("tnt")); + map.put("EntityFallingBlock", new ResourceLocation("falling_block")); + map.put("EntityFireworks", new ResourceLocation("fireworks_rocket")); + map.put("EntityZombieHusk", new ResourceLocation("husk")); + map.put("EntitySpectralArrow", new ResourceLocation("spectral_arrow")); + map.put("EntityShulkerBullet", new ResourceLocation("shulker_bullet")); + map.put("EntityDragonFireball", new ResourceLocation("dragon_fireball")); + map.put("EntityZombieVillager", new ResourceLocation("zombie_villager")); + map.put("EntityHorseSkeleton", new ResourceLocation("skeleton_horse")); + map.put("EntityHorseZombie", new ResourceLocation("zombie_horse")); + map.put("EntityArmorStand", new ResourceLocation("armor_stand")); + map.put("EntityHorseDonkey", new ResourceLocation("donkey")); + map.put("EntityHorseMule", new ResourceLocation("mule")); + map.put("EntityEvokerFangs", new ResourceLocation("evocation_fangs")); + map.put("EntityEvoker", new ResourceLocation("evocation_illager")); + map.put("EntityVex", new ResourceLocation("vex")); + map.put("EntityVindicator", new ResourceLocation("vindication_illager")); + map.put("EntityIllagerIllusioner", new ResourceLocation("illusion_illager")); + map.put("EntityMinecartCommandBlock", new ResourceLocation("commandblock_minecart")); + map.put("EntityBoat", new ResourceLocation("boat")); + map.put("EntityMinecartRideable", new ResourceLocation("minecart")); + map.put("EntityMinecartChest", new ResourceLocation("chest_minecart")); + map.put("EntityMinecartFurnace", new ResourceLocation("furnace_minecart")); + map.put("EntityMinecartTNT", new ResourceLocation("tnt_minecart")); + map.put("EntityMinecartHopper", new ResourceLocation("hopper_minecart")); + map.put("EntityMinecartMobSpawner", new ResourceLocation("spawner_minecart")); + map.put("EntityCreeper", new ResourceLocation("creeper")); + map.put("EntitySkeleton", new ResourceLocation("skeleton")); + map.put("EntitySpider", new ResourceLocation("spider")); + map.put("EntityGiantZombie", new ResourceLocation("giant")); + map.put("EntityZombie", new ResourceLocation("zombie")); + map.put("EntitySlime", new ResourceLocation("slime")); + map.put("EntityGhast", new ResourceLocation("ghast")); + map.put("EntityPigZombie", new ResourceLocation("zombie_pigman")); + map.put("EntityEnderman", new ResourceLocation("enderman")); + map.put("EntityCaveSpider", new ResourceLocation("cave_spider")); + map.put("EntitySilverfish", new ResourceLocation("silverfish")); + map.put("EntityBlaze", new ResourceLocation("blaze")); + map.put("EntityMagmaCube", new ResourceLocation("magma_cube")); + map.put("EntityEnderDragon", new ResourceLocation("ender_dragon")); + map.put("EntityWither", new ResourceLocation("wither")); + map.put("EntityBat", new ResourceLocation("bat")); + map.put("EntityWitch", new ResourceLocation("witch")); + map.put("EntityEndermite", new ResourceLocation("endermite")); + map.put("EntityGuardian", new ResourceLocation("guardian")); + map.put("EntityShulker", new ResourceLocation("shulker")); + map.put("EntityPig", new ResourceLocation("pig")); + map.put("EntitySheep", new ResourceLocation("sheep")); + map.put("EntityCow", new ResourceLocation("cow")); + map.put("EntityChicken", new ResourceLocation("chicken")); + map.put("EntitySquid", new ResourceLocation("squid")); + map.put("EntityWolf", new ResourceLocation("wolf")); + map.put("EntityMushroomCow", new ResourceLocation("mooshroom")); + map.put("EntitySnowman", new ResourceLocation("snowman")); + map.put("EntityOcelot", new ResourceLocation("ocelot")); + map.put("EntityIronGolem", new ResourceLocation("villager_golem")); + map.put("EntityHorse", new ResourceLocation("horse")); + map.put("EntityRabbit", new ResourceLocation("rabbit")); + map.put("EntityPolarBear", new ResourceLocation("polar_bear")); + map.put("EntityLlama", new ResourceLocation("llama")); + map.put("EntityLlamaSpit", new ResourceLocation("llama_spit")); + map.put("EntityParrot", new ResourceLocation("parrot")); + map.put("EntityVillager", new ResourceLocation("villager")); + map.put("EntityEnderCrystal", new ResourceLocation("ender_crystal")); + map.put("TileEntityFurnace", new ResourceLocation("furnace")); + map.put("TileEntityChest", new ResourceLocation("chest")); + map.put("TileEntityEnderChest", new ResourceLocation("ender_chest")); + map.put("TileEntityRecordPlayer", new ResourceLocation("jukebox")); + map.put("TileEntityDispenser", new ResourceLocation("dispenser")); + map.put("TileEntityDropper", new ResourceLocation("dropper")); + map.put("TileEntitySign", new ResourceLocation("sign")); + map.put("TileEntityMobSpawner", new ResourceLocation("mob_spawner")); + map.put("TileEntityNote", new ResourceLocation("noteblock")); + map.put("TileEntityPiston", new ResourceLocation("piston")); + map.put("TileEntityBrewingStand", new ResourceLocation("brewing_stand")); + map.put("TileEntityEnchantTable", new ResourceLocation("enchanting_table")); + map.put("TileEntityEnderPortal", new ResourceLocation("end_portal")); + map.put("TileEntityBeacon", new ResourceLocation("beacon")); + map.put("TileEntitySkull", new ResourceLocation("skull")); + map.put("TileEntityLightDetector", new ResourceLocation("daylight_detector")); + map.put("TileEntityHopper", new ResourceLocation("hopper")); + map.put("TileEntityComparator", new ResourceLocation("comparator")); + map.put("TileEntityFlowerPot", new ResourceLocation("flower_pot")); + map.put("TileEntityBanner", new ResourceLocation("banner")); + map.put("TileEntityStructure", new ResourceLocation("structure_block")); + map.put("TileEntityEndGateway", new ResourceLocation("end_gateway")); + map.put("TileEntityCommand", new ResourceLocation("command_block")); + map.put("TileEntityShulkerBox", new ResourceLocation("shulker_box")); + map.put("TileEntityBed", new ResourceLocation("bed")); + } + + private static ResourceLocation getKey(String type) { + final ResourceLocation key = OLD_ID_TO_KEY_MAP.get(type); + if (key == null) { + throw new IllegalArgumentException("Unknown mapping for " + type); + } + return key; + } + + private static void convertCompound(LegacyType type, net.minecraft.nbt.CompoundTag cmp, String key, int sourceVer, int targetVer) { + cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, targetVer)); + } + + private static void convertItem(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 10)) { + convertCompound(LegacyType.ITEM_INSTANCE, nbttagcompound, key, sourceVer, targetVer); + } + } + + private static void convertItems(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 9)) { + ListTag nbttaglist = nbttagcompound.getList(key, 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.add(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } + + } + + private static class DataConverterEquipment implements DataConverter { + + DataConverterEquipment() { + } + + @Override + public int getDataVersion() { + return 100; + } + + @Override + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + ListTag nbttaglist = cmp.getList("Equipment", 10); + ListTag nbttaglist1; + + if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { + nbttaglist1 = new ListTag(); + nbttaglist1.add(nbttaglist.get(0)); + nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); + cmp.put("HandItems", nbttaglist1); + } + + if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { + nbttaglist1 = new ListTag(); + nbttaglist1.add(nbttaglist.get(1)); + nbttaglist1.add(nbttaglist.get(2)); + nbttaglist1.add(nbttaglist.get(3)); + nbttaglist1.add(nbttaglist.get(4)); + cmp.put("ArmorItems", nbttaglist1); + } + + cmp.remove("Equipment"); + if (cmp.contains("DropChances", 9)) { + nbttaglist1 = cmp.getList("DropChances", 5); + ListTag nbttaglist2; + + if (!cmp.contains("HandDropChances", 10)) { + nbttaglist2 = new ListTag(); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(0))); + nbttaglist2.add(FloatTag.valueOf(0.0F)); + cmp.put("HandDropChances", nbttaglist2); + } + + if (!cmp.contains("ArmorDropChances", 10)) { + nbttaglist2 = new ListTag(); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(1))); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(2))); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(3))); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(4))); + cmp.put("ArmorDropChances", nbttaglist2); + } + + cmp.remove("DropChances"); + } + + return cmp; + } + } + + private static class DataInspectorBlockEntity implements DataInspector { + + private static final Map b = Maps.newHashMap(); + private static final Map c = Maps.newHashMap(); + + DataInspectorBlockEntity() { + } + + @Nullable + private static String convertEntityId(int i, String s) { + String key = new ResourceLocation(s).toString(); + if (i < 515 && DataInspectorBlockEntity.b.containsKey(key)) { + return DataInspectorBlockEntity.b.get(key); + } else { + return DataInspectorBlockEntity.c.get(key); + } + } + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (!cmp.contains("tag", 10)) { + return cmp; + } else { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + String s = cmp.getString("id"); + String s1 = convertEntityId(sourceVer, s); + boolean flag; + + if (s1 == null) { + // CraftBukkit - Remove unnecessary warning (occurs when deserializing a Shulker Box item) + // DataInspectorBlockEntity.a.warn("Unable to resolve BlockEntity for ItemInstance: {}", s); + flag = false; + } else { + flag = !nbttagcompound2.contains("id"); + nbttagcompound2.putString("id", s1); + } + + convert(LegacyType.BLOCK_ENTITY, nbttagcompound2, sourceVer, targetVer); + if (flag) { + nbttagcompound2.remove("id"); + } + } + + return cmp; + } + } + + static { + Map map = DataInspectorBlockEntity.b; + + map.put("minecraft:furnace", "Furnace"); + map.put("minecraft:lit_furnace", "Furnace"); + map.put("minecraft:chest", "Chest"); + map.put("minecraft:trapped_chest", "Chest"); + map.put("minecraft:ender_chest", "EnderChest"); + map.put("minecraft:jukebox", "RecordPlayer"); + map.put("minecraft:dispenser", "Trap"); + map.put("minecraft:dropper", "Dropper"); + map.put("minecraft:sign", "Sign"); + map.put("minecraft:mob_spawner", "MobSpawner"); + map.put("minecraft:noteblock", "Music"); + map.put("minecraft:brewing_stand", "Cauldron"); + map.put("minecraft:enhanting_table", "EnchantTable"); + map.put("minecraft:command_block", "CommandBlock"); + map.put("minecraft:beacon", "Beacon"); + map.put("minecraft:skull", "Skull"); + map.put("minecraft:daylight_detector", "DLDetector"); + map.put("minecraft:hopper", "Hopper"); + map.put("minecraft:banner", "Banner"); + map.put("minecraft:flower_pot", "FlowerPot"); + map.put("minecraft:repeating_command_block", "CommandBlock"); + map.put("minecraft:chain_command_block", "CommandBlock"); + map.put("minecraft:standing_sign", "Sign"); + map.put("minecraft:wall_sign", "Sign"); + map.put("minecraft:piston_head", "Piston"); + map.put("minecraft:daylight_detector_inverted", "DLDetector"); + map.put("minecraft:unpowered_comparator", "Comparator"); + map.put("minecraft:powered_comparator", "Comparator"); + map.put("minecraft:wall_banner", "Banner"); + map.put("minecraft:standing_banner", "Banner"); + map.put("minecraft:structure_block", "Structure"); + map.put("minecraft:end_portal", "Airportal"); + map.put("minecraft:end_gateway", "EndGateway"); + map.put("minecraft:shield", "Shield"); + map = DataInspectorBlockEntity.c; + map.put("minecraft:furnace", "minecraft:furnace"); + map.put("minecraft:lit_furnace", "minecraft:furnace"); + map.put("minecraft:chest", "minecraft:chest"); + map.put("minecraft:trapped_chest", "minecraft:chest"); + map.put("minecraft:ender_chest", "minecraft:enderchest"); + map.put("minecraft:jukebox", "minecraft:jukebox"); + map.put("minecraft:dispenser", "minecraft:dispenser"); + map.put("minecraft:dropper", "minecraft:dropper"); + map.put("minecraft:sign", "minecraft:sign"); + map.put("minecraft:mob_spawner", "minecraft:mob_spawner"); + map.put("minecraft:noteblock", "minecraft:noteblock"); + map.put("minecraft:brewing_stand", "minecraft:brewing_stand"); + map.put("minecraft:enhanting_table", "minecraft:enchanting_table"); + map.put("minecraft:command_block", "minecraft:command_block"); + map.put("minecraft:beacon", "minecraft:beacon"); + map.put("minecraft:skull", "minecraft:skull"); + map.put("minecraft:daylight_detector", "minecraft:daylight_detector"); + map.put("minecraft:hopper", "minecraft:hopper"); + map.put("minecraft:banner", "minecraft:banner"); + map.put("minecraft:flower_pot", "minecraft:flower_pot"); + map.put("minecraft:repeating_command_block", "minecraft:command_block"); + map.put("minecraft:chain_command_block", "minecraft:command_block"); + map.put("minecraft:shulker_box", "minecraft:shulker_box"); + map.put("minecraft:white_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:orange_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:magenta_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:light_blue_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:yellow_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:lime_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:pink_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:gray_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:silver_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:cyan_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:purple_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:blue_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:brown_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:green_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:red_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:black_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:bed", "minecraft:bed"); + map.put("minecraft:standing_sign", "minecraft:sign"); + map.put("minecraft:wall_sign", "minecraft:sign"); + map.put("minecraft:piston_head", "minecraft:piston"); + map.put("minecraft:daylight_detector_inverted", "minecraft:daylight_detector"); + map.put("minecraft:unpowered_comparator", "minecraft:comparator"); + map.put("minecraft:powered_comparator", "minecraft:comparator"); + map.put("minecraft:wall_banner", "minecraft:banner"); + map.put("minecraft:standing_banner", "minecraft:banner"); + map.put("minecraft:structure_block", "minecraft:structure_block"); + map.put("minecraft:end_portal", "minecraft:end_portal"); + map.put("minecraft:end_gateway", "minecraft:end_gateway"); + map.put("minecraft:shield", "minecraft:shield"); + } + } + + private static class DataInspectorEntity implements DataInspector { + + private static final Logger a = LogManager.getLogger(ForgeDataFixer.class); + + DataInspectorEntity() { + } + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("EntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + String s = cmp.getString("id"); + String s1; + + if ("minecraft:armor_stand".equals(s)) { + s1 = sourceVer < 515 ? "ArmorStand" : "minecraft:armor_stand"; + } else { + if (!"minecraft:spawn_egg".equals(s)) { + return cmp; + } + + s1 = nbttagcompound2.getString("id"); + } + + boolean flag; + + if (s1 == null) { + DataInspectorEntity.a.warn("Unable to resolve Entity for ItemInstance: {}", s); + flag = false; + } else { + flag = !nbttagcompound2.contains("id", 8); + nbttagcompound2.putString("id", s1); + } + + convert(LegacyType.ENTITY, nbttagcompound2, sourceVer, targetVer); + if (flag) { + nbttagcompound2.remove("id"); + } + } + + return cmp; + } + } + + + private abstract static class DataInspectorTagged implements DataInspector { + + private final ResourceLocation key; + + DataInspectorTagged(String type) { + this.key = getKey(type); + } + + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (this.key.equals(new ResourceLocation(cmp.getString("id")))) { + cmp = this.inspectChecked(cmp, sourceVer, targetVer); + } + + return cmp; + } + + abstract net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer); + } + + private static class DataInspectorItemList extends DataInspectorTagged { + + private final String[] keys; + + DataInspectorItemList(String oclass, String... astring) { + super(oclass); + this.keys = astring; + } + + net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer) { + for (String s : this.keys) { + ForgeDataFixer.convertItems(nbttagcompound, s, sourceVer, targetVer); + } + + return nbttagcompound; + } + } + + private static class DataInspectorItem extends DataInspectorTagged { + + private final String[] keys; + + DataInspectorItem(String oclass, String... astring) { + super(oclass); + this.keys = astring; + } + + net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer) { + for (String key : this.keys) { + ForgeDataFixer.convertItem(nbttagcompound, key, sourceVer, targetVer); + } + + return nbttagcompound; + } + } + + private static class DataConverterMaterialId implements DataConverter { + + private static final String[] materials = new String[2268]; + + DataConverterMaterialId() { + } + + public int getDataVersion() { + return 102; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.contains("id", 99)) { + short short0 = cmp.getShort("id"); + + if (short0 > 0 && short0 < materials.length && materials[short0] != null) { + cmp.putString("id", materials[short0]); + } + } + + return cmp; + } + + static { + materials[1] = "minecraft:stone"; + materials[2] = "minecraft:grass"; + materials[3] = "minecraft:dirt"; + materials[4] = "minecraft:cobblestone"; + materials[5] = "minecraft:planks"; + materials[6] = "minecraft:sapling"; + materials[7] = "minecraft:bedrock"; + materials[8] = "minecraft:flowing_water"; + materials[9] = "minecraft:water"; + materials[10] = "minecraft:flowing_lava"; + materials[11] = "minecraft:lava"; + materials[12] = "minecraft:sand"; + materials[13] = "minecraft:gravel"; + materials[14] = "minecraft:gold_ore"; + materials[15] = "minecraft:iron_ore"; + materials[16] = "minecraft:coal_ore"; + materials[17] = "minecraft:log"; + materials[18] = "minecraft:leaves"; + materials[19] = "minecraft:sponge"; + materials[20] = "minecraft:glass"; + materials[21] = "minecraft:lapis_ore"; + materials[22] = "minecraft:lapis_block"; + materials[23] = "minecraft:dispenser"; + materials[24] = "minecraft:sandstone"; + materials[25] = "minecraft:noteblock"; + materials[27] = "minecraft:golden_rail"; + materials[28] = "minecraft:detector_rail"; + materials[29] = "minecraft:sticky_piston"; + materials[30] = "minecraft:web"; + materials[31] = "minecraft:tallgrass"; + materials[32] = "minecraft:deadbush"; + materials[33] = "minecraft:piston"; + materials[35] = "minecraft:wool"; + materials[37] = "minecraft:yellow_flower"; + materials[38] = "minecraft:red_flower"; + materials[39] = "minecraft:brown_mushroom"; + materials[40] = "minecraft:red_mushroom"; + materials[41] = "minecraft:gold_block"; + materials[42] = "minecraft:iron_block"; + materials[43] = "minecraft:double_stone_slab"; + materials[44] = "minecraft:stone_slab"; + materials[45] = "minecraft:brick_block"; + materials[46] = "minecraft:tnt"; + materials[47] = "minecraft:bookshelf"; + materials[48] = "minecraft:mossy_cobblestone"; + materials[49] = "minecraft:obsidian"; + materials[50] = "minecraft:torch"; + materials[51] = "minecraft:fire"; + materials[52] = "minecraft:mob_spawner"; + materials[53] = "minecraft:oak_stairs"; + materials[54] = "minecraft:chest"; + materials[56] = "minecraft:diamond_ore"; + materials[57] = "minecraft:diamond_block"; + materials[58] = "minecraft:crafting_table"; + materials[60] = "minecraft:farmland"; + materials[61] = "minecraft:furnace"; + materials[62] = "minecraft:lit_furnace"; + materials[65] = "minecraft:ladder"; + materials[66] = "minecraft:rail"; + materials[67] = "minecraft:stone_stairs"; + materials[69] = "minecraft:lever"; + materials[70] = "minecraft:stone_pressure_plate"; + materials[72] = "minecraft:wooden_pressure_plate"; + materials[73] = "minecraft:redstone_ore"; + materials[76] = "minecraft:redstone_torch"; + materials[77] = "minecraft:stone_button"; + materials[78] = "minecraft:snow_layer"; + materials[79] = "minecraft:ice"; + materials[80] = "minecraft:snow"; + materials[81] = "minecraft:cactus"; + materials[82] = "minecraft:clay"; + materials[84] = "minecraft:jukebox"; + materials[85] = "minecraft:fence"; + materials[86] = "minecraft:pumpkin"; + materials[87] = "minecraft:netherrack"; + materials[88] = "minecraft:soul_sand"; + materials[89] = "minecraft:glowstone"; + materials[90] = "minecraft:portal"; + materials[91] = "minecraft:lit_pumpkin"; + materials[95] = "minecraft:stained_glass"; + materials[96] = "minecraft:trapdoor"; + materials[97] = "minecraft:monster_egg"; + materials[98] = "minecraft:stonebrick"; + materials[99] = "minecraft:brown_mushroom_block"; + materials[100] = "minecraft:red_mushroom_block"; + materials[101] = "minecraft:iron_bars"; + materials[102] = "minecraft:glass_pane"; + materials[103] = "minecraft:melon_block"; + materials[106] = "minecraft:vine"; + materials[107] = "minecraft:fence_gate"; + materials[108] = "minecraft:brick_stairs"; + materials[109] = "minecraft:stone_brick_stairs"; + materials[110] = "minecraft:mycelium"; + materials[111] = "minecraft:waterlily"; + materials[112] = "minecraft:nether_brick"; + materials[113] = "minecraft:nether_brick_fence"; + materials[114] = "minecraft:nether_brick_stairs"; + materials[116] = "minecraft:enchanting_table"; + materials[119] = "minecraft:end_portal"; + materials[120] = "minecraft:end_portal_frame"; + materials[121] = "minecraft:end_stone"; + materials[122] = "minecraft:dragon_egg"; + materials[123] = "minecraft:redstone_lamp"; + materials[125] = "minecraft:double_wooden_slab"; + materials[126] = "minecraft:wooden_slab"; + materials[127] = "minecraft:cocoa"; + materials[128] = "minecraft:sandstone_stairs"; + materials[129] = "minecraft:emerald_ore"; + materials[130] = "minecraft:ender_chest"; + materials[131] = "minecraft:tripwire_hook"; + materials[133] = "minecraft:emerald_block"; + materials[134] = "minecraft:spruce_stairs"; + materials[135] = "minecraft:birch_stairs"; + materials[136] = "minecraft:jungle_stairs"; + materials[137] = "minecraft:command_block"; + materials[138] = "minecraft:beacon"; + materials[139] = "minecraft:cobblestone_wall"; + materials[141] = "minecraft:carrots"; + materials[142] = "minecraft:potatoes"; + materials[143] = "minecraft:wooden_button"; + materials[145] = "minecraft:anvil"; + materials[146] = "minecraft:trapped_chest"; + materials[147] = "minecraft:light_weighted_pressure_plate"; + materials[148] = "minecraft:heavy_weighted_pressure_plate"; + materials[151] = "minecraft:daylight_detector"; + materials[152] = "minecraft:redstone_block"; + materials[153] = "minecraft:quartz_ore"; + materials[154] = "minecraft:hopper"; + materials[155] = "minecraft:quartz_block"; + materials[156] = "minecraft:quartz_stairs"; + materials[157] = "minecraft:activator_rail"; + materials[158] = "minecraft:dropper"; + materials[159] = "minecraft:stained_hardened_clay"; + materials[160] = "minecraft:stained_glass_pane"; + materials[161] = "minecraft:leaves2"; + materials[162] = "minecraft:log2"; + materials[163] = "minecraft:acacia_stairs"; + materials[164] = "minecraft:dark_oak_stairs"; + materials[170] = "minecraft:hay_block"; + materials[171] = "minecraft:carpet"; + materials[172] = "minecraft:hardened_clay"; + materials[173] = "minecraft:coal_block"; + materials[174] = "minecraft:packed_ice"; + materials[175] = "minecraft:double_plant"; + materials[256] = "minecraft:iron_shovel"; + materials[257] = "minecraft:iron_pickaxe"; + materials[258] = "minecraft:iron_axe"; + materials[259] = "minecraft:flint_and_steel"; + materials[260] = "minecraft:apple"; + materials[261] = "minecraft:bow"; + materials[262] = "minecraft:arrow"; + materials[263] = "minecraft:coal"; + materials[264] = "minecraft:diamond"; + materials[265] = "minecraft:iron_ingot"; + materials[266] = "minecraft:gold_ingot"; + materials[267] = "minecraft:iron_sword"; + materials[268] = "minecraft:wooden_sword"; + materials[269] = "minecraft:wooden_shovel"; + materials[270] = "minecraft:wooden_pickaxe"; + materials[271] = "minecraft:wooden_axe"; + materials[272] = "minecraft:stone_sword"; + materials[273] = "minecraft:stone_shovel"; + materials[274] = "minecraft:stone_pickaxe"; + materials[275] = "minecraft:stone_axe"; + materials[276] = "minecraft:diamond_sword"; + materials[277] = "minecraft:diamond_shovel"; + materials[278] = "minecraft:diamond_pickaxe"; + materials[279] = "minecraft:diamond_axe"; + materials[280] = "minecraft:stick"; + materials[281] = "minecraft:bowl"; + materials[282] = "minecraft:mushroom_stew"; + materials[283] = "minecraft:golden_sword"; + materials[284] = "minecraft:golden_shovel"; + materials[285] = "minecraft:golden_pickaxe"; + materials[286] = "minecraft:golden_axe"; + materials[287] = "minecraft:string"; + materials[288] = "minecraft:feather"; + materials[289] = "minecraft:gunpowder"; + materials[290] = "minecraft:wooden_hoe"; + materials[291] = "minecraft:stone_hoe"; + materials[292] = "minecraft:iron_hoe"; + materials[293] = "minecraft:diamond_hoe"; + materials[294] = "minecraft:golden_hoe"; + materials[295] = "minecraft:wheat_seeds"; + materials[296] = "minecraft:wheat"; + materials[297] = "minecraft:bread"; + materials[298] = "minecraft:leather_helmet"; + materials[299] = "minecraft:leather_chestplate"; + materials[300] = "minecraft:leather_leggings"; + materials[301] = "minecraft:leather_boots"; + materials[302] = "minecraft:chainmail_helmet"; + materials[303] = "minecraft:chainmail_chestplate"; + materials[304] = "minecraft:chainmail_leggings"; + materials[305] = "minecraft:chainmail_boots"; + materials[306] = "minecraft:iron_helmet"; + materials[307] = "minecraft:iron_chestplate"; + materials[308] = "minecraft:iron_leggings"; + materials[309] = "minecraft:iron_boots"; + materials[310] = "minecraft:diamond_helmet"; + materials[311] = "minecraft:diamond_chestplate"; + materials[312] = "minecraft:diamond_leggings"; + materials[313] = "minecraft:diamond_boots"; + materials[314] = "minecraft:golden_helmet"; + materials[315] = "minecraft:golden_chestplate"; + materials[316] = "minecraft:golden_leggings"; + materials[317] = "minecraft:golden_boots"; + materials[318] = "minecraft:flint"; + materials[319] = "minecraft:porkchop"; + materials[320] = "minecraft:cooked_porkchop"; + materials[321] = "minecraft:painting"; + materials[322] = "minecraft:golden_apple"; + materials[323] = "minecraft:sign"; + materials[324] = "minecraft:wooden_door"; + materials[325] = "minecraft:bucket"; + materials[326] = "minecraft:water_bucket"; + materials[327] = "minecraft:lava_bucket"; + materials[328] = "minecraft:minecart"; + materials[329] = "minecraft:saddle"; + materials[330] = "minecraft:iron_door"; + materials[331] = "minecraft:redstone"; + materials[332] = "minecraft:snowball"; + materials[333] = "minecraft:boat"; + materials[334] = "minecraft:leather"; + materials[335] = "minecraft:milk_bucket"; + materials[336] = "minecraft:brick"; + materials[337] = "minecraft:clay_ball"; + materials[338] = "minecraft:reeds"; + materials[339] = "minecraft:paper"; + materials[340] = "minecraft:book"; + materials[341] = "minecraft:slime_ball"; + materials[342] = "minecraft:chest_minecart"; + materials[343] = "minecraft:furnace_minecart"; + materials[344] = "minecraft:egg"; + materials[345] = "minecraft:compass"; + materials[346] = "minecraft:fishing_rod"; + materials[347] = "minecraft:clock"; + materials[348] = "minecraft:glowstone_dust"; + materials[349] = "minecraft:fish"; + materials[350] = "minecraft:cooked_fish"; // Paper - cooked_fished -> cooked_fish + materials[351] = "minecraft:dye"; + materials[352] = "minecraft:bone"; + materials[353] = "minecraft:sugar"; + materials[354] = "minecraft:cake"; + materials[355] = "minecraft:bed"; + materials[356] = "minecraft:repeater"; + materials[357] = "minecraft:cookie"; + materials[358] = "minecraft:filled_map"; + materials[359] = "minecraft:shears"; + materials[360] = "minecraft:melon"; + materials[361] = "minecraft:pumpkin_seeds"; + materials[362] = "minecraft:melon_seeds"; + materials[363] = "minecraft:beef"; + materials[364] = "minecraft:cooked_beef"; + materials[365] = "minecraft:chicken"; + materials[366] = "minecraft:cooked_chicken"; + materials[367] = "minecraft:rotten_flesh"; + materials[368] = "minecraft:ender_pearl"; + materials[369] = "minecraft:blaze_rod"; + materials[370] = "minecraft:ghast_tear"; + materials[371] = "minecraft:gold_nugget"; + materials[372] = "minecraft:nether_wart"; + materials[373] = "minecraft:potion"; + materials[374] = "minecraft:glass_bottle"; + materials[375] = "minecraft:spider_eye"; + materials[376] = "minecraft:fermented_spider_eye"; + materials[377] = "minecraft:blaze_powder"; + materials[378] = "minecraft:magma_cream"; + materials[379] = "minecraft:brewing_stand"; + materials[380] = "minecraft:cauldron"; + materials[381] = "minecraft:ender_eye"; + materials[382] = "minecraft:speckled_melon"; + materials[383] = "minecraft:spawn_egg"; + materials[384] = "minecraft:experience_bottle"; + materials[385] = "minecraft:fire_charge"; + materials[386] = "minecraft:writable_book"; + materials[387] = "minecraft:written_book"; + materials[388] = "minecraft:emerald"; + materials[389] = "minecraft:item_frame"; + materials[390] = "minecraft:flower_pot"; + materials[391] = "minecraft:carrot"; + materials[392] = "minecraft:potato"; + materials[393] = "minecraft:baked_potato"; + materials[394] = "minecraft:poisonous_potato"; + materials[395] = "minecraft:map"; + materials[396] = "minecraft:golden_carrot"; + materials[397] = "minecraft:skull"; + materials[398] = "minecraft:carrot_on_a_stick"; + materials[399] = "minecraft:nether_star"; + materials[400] = "minecraft:pumpkin_pie"; + materials[401] = "minecraft:fireworks"; + materials[402] = "minecraft:firework_charge"; + materials[403] = "minecraft:enchanted_book"; + materials[404] = "minecraft:comparator"; + materials[405] = "minecraft:netherbrick"; + materials[406] = "minecraft:quartz"; + materials[407] = "minecraft:tnt_minecart"; + materials[408] = "minecraft:hopper_minecart"; + materials[417] = "minecraft:iron_horse_armor"; + materials[418] = "minecraft:golden_horse_armor"; + materials[419] = "minecraft:diamond_horse_armor"; + materials[420] = "minecraft:lead"; + materials[421] = "minecraft:name_tag"; + materials[422] = "minecraft:command_block_minecart"; + materials[2256] = "minecraft:record_13"; + materials[2257] = "minecraft:record_cat"; + materials[2258] = "minecraft:record_blocks"; + materials[2259] = "minecraft:record_chirp"; + materials[2260] = "minecraft:record_far"; + materials[2261] = "minecraft:record_mall"; + materials[2262] = "minecraft:record_mellohi"; + materials[2263] = "minecraft:record_stal"; + materials[2264] = "minecraft:record_strad"; + materials[2265] = "minecraft:record_ward"; + materials[2266] = "minecraft:record_11"; + materials[2267] = "minecraft:record_wait"; + } + } + + private static class DataConverterArmorStand implements DataConverter { + + DataConverterArmorStand() { + } + + public int getDataVersion() { + return 147; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("ArmorStand".equals(cmp.getString("id")) && cmp.getBoolean("Silent") && !cmp.getBoolean("Marker")) { + cmp.remove("Silent"); + } + + return cmp; + } + } + + private static class DataConverterBanner implements DataConverter { + + DataConverterBanner() { + } + + public int getDataVersion() { + return 804; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:banner".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.contains("Base", 99)) { + cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); + if (nbttagcompound1.contains("display", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); + + if (nbttagcompound3.contains("Lore", 9)) { + ListTag nbttaglist = nbttagcompound3.getList("Lore", 8); + + if (nbttaglist.size() == 1 && "(+NBT)".equals(nbttaglist.getString(0))) { + return cmp; + } + } + } + + nbttagcompound2.remove("Base"); + if (nbttagcompound2.isEmpty()) { + nbttagcompound1.remove("BlockEntityTag"); + } + + if (nbttagcompound1.isEmpty()) { + cmp.remove("tag"); + } + } + } + } + + return cmp; + } + } + + private static class DataConverterPotionId implements DataConverter { + + private static final String[] potions = new String[128]; + + DataConverterPotionId() { + } + + public int getDataVersion() { + return 102; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:potion".equals(cmp.getString("id"))) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + short short0 = cmp.getShort("Damage"); + + if (!nbttagcompound1.contains("Potion", 8)) { + String s = DataConverterPotionId.potions[short0 & 127]; + + nbttagcompound1.putString("Potion", s == null ? "minecraft:water" : s); + cmp.put("tag", nbttagcompound1); + if ((short0 & 16384) == 16384) { + cmp.putString("id", "minecraft:splash_potion"); + } + } + + if (short0 != 0) { + cmp.putShort("Damage", (short) 0); + } + } + + return cmp; + } + + static { + DataConverterPotionId.potions[0] = "minecraft:water"; + DataConverterPotionId.potions[1] = "minecraft:regeneration"; + DataConverterPotionId.potions[2] = "minecraft:swiftness"; + DataConverterPotionId.potions[3] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[4] = "minecraft:poison"; + DataConverterPotionId.potions[5] = "minecraft:healing"; + DataConverterPotionId.potions[6] = "minecraft:night_vision"; + DataConverterPotionId.potions[7] = null; + DataConverterPotionId.potions[8] = "minecraft:weakness"; + DataConverterPotionId.potions[9] = "minecraft:strength"; + DataConverterPotionId.potions[10] = "minecraft:slowness"; + DataConverterPotionId.potions[11] = "minecraft:leaping"; + DataConverterPotionId.potions[12] = "minecraft:harming"; + DataConverterPotionId.potions[13] = "minecraft:water_breathing"; + DataConverterPotionId.potions[14] = "minecraft:invisibility"; + DataConverterPotionId.potions[15] = null; + DataConverterPotionId.potions[16] = "minecraft:awkward"; + DataConverterPotionId.potions[17] = "minecraft:regeneration"; + DataConverterPotionId.potions[18] = "minecraft:swiftness"; + DataConverterPotionId.potions[19] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[20] = "minecraft:poison"; + DataConverterPotionId.potions[21] = "minecraft:healing"; + DataConverterPotionId.potions[22] = "minecraft:night_vision"; + DataConverterPotionId.potions[23] = null; + DataConverterPotionId.potions[24] = "minecraft:weakness"; + DataConverterPotionId.potions[25] = "minecraft:strength"; + DataConverterPotionId.potions[26] = "minecraft:slowness"; + DataConverterPotionId.potions[27] = "minecraft:leaping"; + DataConverterPotionId.potions[28] = "minecraft:harming"; + DataConverterPotionId.potions[29] = "minecraft:water_breathing"; + DataConverterPotionId.potions[30] = "minecraft:invisibility"; + DataConverterPotionId.potions[31] = null; + DataConverterPotionId.potions[32] = "minecraft:thick"; + DataConverterPotionId.potions[33] = "minecraft:strong_regeneration"; + DataConverterPotionId.potions[34] = "minecraft:strong_swiftness"; + DataConverterPotionId.potions[35] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[36] = "minecraft:strong_poison"; + DataConverterPotionId.potions[37] = "minecraft:strong_healing"; + DataConverterPotionId.potions[38] = "minecraft:night_vision"; + DataConverterPotionId.potions[39] = null; + DataConverterPotionId.potions[40] = "minecraft:weakness"; + DataConverterPotionId.potions[41] = "minecraft:strong_strength"; + DataConverterPotionId.potions[42] = "minecraft:slowness"; + DataConverterPotionId.potions[43] = "minecraft:strong_leaping"; + DataConverterPotionId.potions[44] = "minecraft:strong_harming"; + DataConverterPotionId.potions[45] = "minecraft:water_breathing"; + DataConverterPotionId.potions[46] = "minecraft:invisibility"; + DataConverterPotionId.potions[47] = null; + DataConverterPotionId.potions[48] = null; + DataConverterPotionId.potions[49] = "minecraft:strong_regeneration"; + DataConverterPotionId.potions[50] = "minecraft:strong_swiftness"; + DataConverterPotionId.potions[51] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[52] = "minecraft:strong_poison"; + DataConverterPotionId.potions[53] = "minecraft:strong_healing"; + DataConverterPotionId.potions[54] = "minecraft:night_vision"; + DataConverterPotionId.potions[55] = null; + DataConverterPotionId.potions[56] = "minecraft:weakness"; + DataConverterPotionId.potions[57] = "minecraft:strong_strength"; + DataConverterPotionId.potions[58] = "minecraft:slowness"; + DataConverterPotionId.potions[59] = "minecraft:strong_leaping"; + DataConverterPotionId.potions[60] = "minecraft:strong_harming"; + DataConverterPotionId.potions[61] = "minecraft:water_breathing"; + DataConverterPotionId.potions[62] = "minecraft:invisibility"; + DataConverterPotionId.potions[63] = null; + DataConverterPotionId.potions[64] = "minecraft:mundane"; + DataConverterPotionId.potions[65] = "minecraft:long_regeneration"; + DataConverterPotionId.potions[66] = "minecraft:long_swiftness"; + DataConverterPotionId.potions[67] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[68] = "minecraft:long_poison"; + DataConverterPotionId.potions[69] = "minecraft:healing"; + DataConverterPotionId.potions[70] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[71] = null; + DataConverterPotionId.potions[72] = "minecraft:long_weakness"; + DataConverterPotionId.potions[73] = "minecraft:long_strength"; + DataConverterPotionId.potions[74] = "minecraft:long_slowness"; + DataConverterPotionId.potions[75] = "minecraft:long_leaping"; + DataConverterPotionId.potions[76] = "minecraft:harming"; + DataConverterPotionId.potions[77] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[78] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[79] = null; + DataConverterPotionId.potions[80] = "minecraft:awkward"; + DataConverterPotionId.potions[81] = "minecraft:long_regeneration"; + DataConverterPotionId.potions[82] = "minecraft:long_swiftness"; + DataConverterPotionId.potions[83] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[84] = "minecraft:long_poison"; + DataConverterPotionId.potions[85] = "minecraft:healing"; + DataConverterPotionId.potions[86] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[87] = null; + DataConverterPotionId.potions[88] = "minecraft:long_weakness"; + DataConverterPotionId.potions[89] = "minecraft:long_strength"; + DataConverterPotionId.potions[90] = "minecraft:long_slowness"; + DataConverterPotionId.potions[91] = "minecraft:long_leaping"; + DataConverterPotionId.potions[92] = "minecraft:harming"; + DataConverterPotionId.potions[93] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[94] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[95] = null; + DataConverterPotionId.potions[96] = "minecraft:thick"; + DataConverterPotionId.potions[97] = "minecraft:regeneration"; + DataConverterPotionId.potions[98] = "minecraft:swiftness"; + DataConverterPotionId.potions[99] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[100] = "minecraft:poison"; + DataConverterPotionId.potions[101] = "minecraft:strong_healing"; + DataConverterPotionId.potions[102] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[103] = null; + DataConverterPotionId.potions[104] = "minecraft:long_weakness"; + DataConverterPotionId.potions[105] = "minecraft:strength"; + DataConverterPotionId.potions[106] = "minecraft:long_slowness"; + DataConverterPotionId.potions[107] = "minecraft:leaping"; + DataConverterPotionId.potions[108] = "minecraft:strong_harming"; + DataConverterPotionId.potions[109] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[110] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[111] = null; + DataConverterPotionId.potions[112] = null; + DataConverterPotionId.potions[113] = "minecraft:regeneration"; + DataConverterPotionId.potions[114] = "minecraft:swiftness"; + DataConverterPotionId.potions[115] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[116] = "minecraft:poison"; + DataConverterPotionId.potions[117] = "minecraft:strong_healing"; + DataConverterPotionId.potions[118] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[119] = null; + DataConverterPotionId.potions[120] = "minecraft:long_weakness"; + DataConverterPotionId.potions[121] = "minecraft:strength"; + DataConverterPotionId.potions[122] = "minecraft:long_slowness"; + DataConverterPotionId.potions[123] = "minecraft:leaping"; + DataConverterPotionId.potions[124] = "minecraft:strong_harming"; + DataConverterPotionId.potions[125] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[126] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[127] = null; + } + } + + private static class DataConverterSpawnEgg implements DataConverter { + + private static final String[] eggs = new String[256]; + + DataConverterSpawnEgg() { + } + + public int getDataVersion() { + return 105; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:spawn_egg".equals(cmp.getString("id"))) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + short short0 = cmp.getShort("Damage"); + + if (!nbttagcompound2.contains("id", 8)) { + String s = DataConverterSpawnEgg.eggs[short0 & 255]; + + if (s != null) { + nbttagcompound2.putString("id", s); + nbttagcompound1.put("EntityTag", nbttagcompound2); + cmp.put("tag", nbttagcompound1); + } + } + + if (short0 != 0) { + cmp.putShort("Damage", (short) 0); + } + } + + return cmp; + } + + static { + + DataConverterSpawnEgg.eggs[1] = "Item"; + DataConverterSpawnEgg.eggs[2] = "XPOrb"; + DataConverterSpawnEgg.eggs[7] = "ThrownEgg"; + DataConverterSpawnEgg.eggs[8] = "LeashKnot"; + DataConverterSpawnEgg.eggs[9] = "Painting"; + DataConverterSpawnEgg.eggs[10] = "Arrow"; + DataConverterSpawnEgg.eggs[11] = "Snowball"; + DataConverterSpawnEgg.eggs[12] = "Fireball"; + DataConverterSpawnEgg.eggs[13] = "SmallFireball"; + DataConverterSpawnEgg.eggs[14] = "ThrownEnderpearl"; + DataConverterSpawnEgg.eggs[15] = "EyeOfEnderSignal"; + DataConverterSpawnEgg.eggs[16] = "ThrownPotion"; + DataConverterSpawnEgg.eggs[17] = "ThrownExpBottle"; + DataConverterSpawnEgg.eggs[18] = "ItemFrame"; + DataConverterSpawnEgg.eggs[19] = "WitherSkull"; + DataConverterSpawnEgg.eggs[20] = "PrimedTnt"; + DataConverterSpawnEgg.eggs[21] = "FallingSand"; + DataConverterSpawnEgg.eggs[22] = "FireworksRocketEntity"; + DataConverterSpawnEgg.eggs[23] = "TippedArrow"; + DataConverterSpawnEgg.eggs[24] = "SpectralArrow"; + DataConverterSpawnEgg.eggs[25] = "ShulkerBullet"; + DataConverterSpawnEgg.eggs[26] = "DragonFireball"; + DataConverterSpawnEgg.eggs[30] = "ArmorStand"; + DataConverterSpawnEgg.eggs[41] = "Boat"; + DataConverterSpawnEgg.eggs[42] = "MinecartRideable"; + DataConverterSpawnEgg.eggs[43] = "MinecartChest"; + DataConverterSpawnEgg.eggs[44] = "MinecartFurnace"; + DataConverterSpawnEgg.eggs[45] = "MinecartTNT"; + DataConverterSpawnEgg.eggs[46] = "MinecartHopper"; + DataConverterSpawnEgg.eggs[47] = "MinecartSpawner"; + DataConverterSpawnEgg.eggs[40] = "MinecartCommandBlock"; + DataConverterSpawnEgg.eggs[48] = "Mob"; + DataConverterSpawnEgg.eggs[49] = "Monster"; + DataConverterSpawnEgg.eggs[50] = "Creeper"; + DataConverterSpawnEgg.eggs[51] = "Skeleton"; + DataConverterSpawnEgg.eggs[52] = "Spider"; + DataConverterSpawnEgg.eggs[53] = "Giant"; + DataConverterSpawnEgg.eggs[54] = "Zombie"; + DataConverterSpawnEgg.eggs[55] = "Slime"; + DataConverterSpawnEgg.eggs[56] = "Ghast"; + DataConverterSpawnEgg.eggs[57] = "PigZombie"; + DataConverterSpawnEgg.eggs[58] = "Enderman"; + DataConverterSpawnEgg.eggs[59] = "CaveSpider"; + DataConverterSpawnEgg.eggs[60] = "Silverfish"; + DataConverterSpawnEgg.eggs[61] = "Blaze"; + DataConverterSpawnEgg.eggs[62] = "LavaSlime"; + DataConverterSpawnEgg.eggs[63] = "EnderDragon"; + DataConverterSpawnEgg.eggs[64] = "WitherBoss"; + DataConverterSpawnEgg.eggs[65] = "Bat"; + DataConverterSpawnEgg.eggs[66] = "Witch"; + DataConverterSpawnEgg.eggs[67] = "Endermite"; + DataConverterSpawnEgg.eggs[68] = "Guardian"; + DataConverterSpawnEgg.eggs[69] = "Shulker"; + DataConverterSpawnEgg.eggs[90] = "Pig"; + DataConverterSpawnEgg.eggs[91] = "Sheep"; + DataConverterSpawnEgg.eggs[92] = "Cow"; + DataConverterSpawnEgg.eggs[93] = "Chicken"; + DataConverterSpawnEgg.eggs[94] = "Squid"; + DataConverterSpawnEgg.eggs[95] = "Wolf"; + DataConverterSpawnEgg.eggs[96] = "MushroomCow"; + DataConverterSpawnEgg.eggs[97] = "SnowMan"; + DataConverterSpawnEgg.eggs[98] = "Ozelot"; + DataConverterSpawnEgg.eggs[99] = "VillagerGolem"; + DataConverterSpawnEgg.eggs[100] = "EntityHorse"; + DataConverterSpawnEgg.eggs[101] = "Rabbit"; + DataConverterSpawnEgg.eggs[120] = "Villager"; + DataConverterSpawnEgg.eggs[200] = "EnderCrystal"; + } + } + + private static class DataConverterMinecart implements DataConverter { + + private static final List a = Lists.newArrayList(new String[] { "MinecartRideable", "MinecartChest", "MinecartFurnace", "MinecartTNT", "MinecartSpawner", "MinecartHopper", "MinecartCommandBlock" }); + + DataConverterMinecart() { + } + + public int getDataVersion() { + return 106; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Minecart".equals(cmp.getString("id"))) { + String s = "MinecartRideable"; + int i = cmp.getInt("Type"); + + if (i > 0 && i < DataConverterMinecart.a.size()) { + s = DataConverterMinecart.a.get(i); + } + + cmp.putString("id", s); + cmp.remove("Type"); + } + + return cmp; + } + } + + private static class DataConverterMobSpawner implements DataConverter { + + DataConverterMobSpawner() { + } + + public int getDataVersion() { + return 107; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (!"MobSpawner".equals(cmp.getString("id"))) { + return cmp; + } else { + if (cmp.contains("EntityId", 8)) { + String s = cmp.getString("EntityId"); + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("SpawnData"); + + nbttagcompound1.putString("id", s.isEmpty() ? "Pig" : s); + cmp.put("SpawnData", nbttagcompound1); + cmp.remove("EntityId"); + } + + if (cmp.contains("SpawnPotentials", 9)) { + ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int i = 0; i < nbttaglist.size(); ++i) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); + + if (nbttagcompound2.contains("Type", 8)) { + net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound2.getCompound("Properties"); + + nbttagcompound3.putString("id", nbttagcompound2.getString("Type")); + nbttagcompound2.put("Entity", nbttagcompound3); + nbttagcompound2.remove("Type"); + nbttagcompound2.remove("Properties"); + } + } + } + + return cmp; + } + } + } + + private static class DataConverterUUID implements DataConverter { + + DataConverterUUID() { + } + + public int getDataVersion() { + return 108; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.contains("UUID", 8)) { + cmp.putUUID("UUID", UUID.fromString(cmp.getString("UUID"))); + } + + return cmp; + } + } + + private static class DataConverterHealth implements DataConverter { + + private static final Set a = 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" }); + + DataConverterHealth() { + } + + public int getDataVersion() { + return 109; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (DataConverterHealth.a.contains(cmp.getString("id"))) { + float f; + + if (cmp.contains("HealF", 99)) { + f = cmp.getFloat("HealF"); + cmp.remove("HealF"); + } else { + if (!cmp.contains("Health", 99)) { + return cmp; + } + + f = cmp.getFloat("Health"); + } + + cmp.putFloat("Health", f); + } + + return cmp; + } + } + + private static class DataConverterSaddle implements DataConverter { + + DataConverterSaddle() { + } + + public int getDataVersion() { + return 110; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("SaddleItem", 10) && cmp.getBoolean("Saddle")) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = new net.minecraft.nbt.CompoundTag(); + + nbttagcompound1.putString("id", "minecraft:saddle"); + nbttagcompound1.putByte("Count", (byte) 1); + nbttagcompound1.putShort("Damage", (short) 0); + cmp.put("SaddleItem", nbttagcompound1); + cmp.remove("Saddle"); + } + + return cmp; + } + } + + private static class DataConverterHanging implements DataConverter { + + DataConverterHanging() { + } + + public int getDataVersion() { + return 111; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = cmp.getString("id"); + boolean flag = "Painting".equals(s); + boolean flag1 = "ItemFrame".equals(s); + + if ((flag || flag1) && !cmp.contains("Facing", 99)) { + Direction enumdirection; + + if (cmp.contains("Direction", 99)) { + enumdirection = Direction.from2DDataValue(cmp.getByte("Direction")); + cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); + cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); + cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); + cmp.remove("Direction"); + if (flag1 && cmp.contains("ItemRotation", 99)) { + cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); + } + } else { + enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); + cmp.remove("Dir"); + } + + cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); + } + + return cmp; + } + } + + private static class DataConverterDropChances implements DataConverter { + + DataConverterDropChances() { + } + + public int getDataVersion() { + return 113; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + ListTag nbttaglist; + + if (cmp.contains("HandDropChances", 9)) { + nbttaglist = cmp.getList("HandDropChances", 5); + if (nbttaglist.size() == 2 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F) { + cmp.remove("HandDropChances"); + } + } + + if (cmp.contains("ArmorDropChances", 9)) { + nbttaglist = cmp.getList("ArmorDropChances", 5); + if (nbttaglist.size() == 4 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F && nbttaglist.getFloat(2) == 0.0F && nbttaglist.getFloat(3) == 0.0F) { + cmp.remove("ArmorDropChances"); + } + } + + return cmp; + } + } + + private static class DataConverterRiding implements DataConverter { + + DataConverterRiding() { + } + + public int getDataVersion() { + return 135; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + while (cmp.contains("Riding", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = this.b(cmp); + + this.convert(cmp, nbttagcompound1); + cmp = nbttagcompound1; + } + + return cmp; + } + + protected void convert(net.minecraft.nbt.CompoundTag nbttagcompound, net.minecraft.nbt.CompoundTag nbttagcompound1) { + ListTag nbttaglist = new ListTag(); + + nbttaglist.add(nbttagcompound); + nbttagcompound1.put("Passengers", nbttaglist); + } + + protected net.minecraft.nbt.CompoundTag b(net.minecraft.nbt.CompoundTag nbttagcompound) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = nbttagcompound.getCompound("Riding"); + + nbttagcompound.remove("Riding"); + return nbttagcompound1; + } + } + + private static class DataConverterBook implements DataConverter { + + DataConverterBook() { + } + + public int getDataVersion() { + return 165; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:written_book".equals(cmp.getString("id"))) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("pages", 9)) { + ListTag nbttaglist = nbttagcompound1.getList("pages", 8); + + for (int i = 0; i < nbttaglist.size(); ++i) { + String s = nbttaglist.getString(i); + Object object = null; + + if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { + if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { + object = Component.literal(s); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); + if (object == null) { + object = Component.literal(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = Component.literal(s); + } + } + } else { + object = Component.literal(""); + } + + nbttaglist.set(i, StringTag.valueOf(Component.Serializer.toJson((Component) object))); + } + + nbttagcompound1.put("pages", nbttaglist); + } + } + + return cmp; + } + } + + private static class DataConverterCookedFish implements DataConverter { + + private static final ResourceLocation a = new ResourceLocation("cooked_fished"); + + DataConverterCookedFish() { + } + + public int getDataVersion() { + return 502; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.contains("id", 8) && DataConverterCookedFish.a.equals(new ResourceLocation(cmp.getString("id")))) { + cmp.putString("id", "minecraft:cooked_fish"); + } + + return cmp; + } + } + + private static class DataConverterZombie implements DataConverter { + + private static final Random a = new Random(); + + DataConverterZombie() { + } + + public int getDataVersion() { + return 502; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Zombie".equals(cmp.getString("id")) && cmp.getBoolean("IsVillager")) { + if (!cmp.contains("ZombieType", 99)) { + int i = -1; + + if (cmp.contains("VillagerProfession", 99)) { + try { + i = this.convert(cmp.getInt("VillagerProfession")); + } catch (RuntimeException runtimeexception) { + ; + } + } + + if (i == -1) { + i = this.convert(DataConverterZombie.a.nextInt(6)); + } + + cmp.putInt("ZombieType", i); + } + + cmp.remove("IsVillager"); + } + + return cmp; + } + + private int convert(int i) { + return i >= 0 && i < 6 ? i : -1; + } + } + + private static class DataConverterVBO implements DataConverter { + + DataConverterVBO() { + } + + public int getDataVersion() { + return 505; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + cmp.putString("useVbo", "true"); + return cmp; + } + } + + private static class DataConverterGuardian implements DataConverter { + + DataConverterGuardian() { + } + + public int getDataVersion() { + return 700; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Guardian".equals(cmp.getString("id"))) { + if (cmp.getBoolean("Elder")) { + cmp.putString("id", "ElderGuardian"); + } + + cmp.remove("Elder"); + } + + return cmp; + } + } + + private static class DataConverterSkeleton implements DataConverter { + + DataConverterSkeleton() { + } + + public int getDataVersion() { + return 701; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = cmp.getString("id"); + + if ("Skeleton".equals(s)) { + int i = cmp.getInt("SkeletonType"); + + if (i == 1) { + cmp.putString("id", "WitherSkeleton"); + } else if (i == 2) { + cmp.putString("id", "Stray"); + } + + cmp.remove("SkeletonType"); + } + + return cmp; + } + } + + private static class DataConverterZombieType implements DataConverter { + + DataConverterZombieType() { + } + + public int getDataVersion() { + return 702; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Zombie".equals(cmp.getString("id"))) { + int i = cmp.getInt("ZombieType"); + + switch (i) { + case 1: + case 2: + case 3: + case 4: + case 5: + cmp.putString("id", "ZombieVillager"); + cmp.putInt("Profession", i - 1); + break; + case 6: + cmp.putString("id", "Husk"); + case 0: + default: + break; + } + + cmp.remove("ZombieType"); + } + + return cmp; + } + } + + private static class DataConverterHorse implements DataConverter { + + DataConverterHorse() { + } + + public int getDataVersion() { + return 703; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id"))) { + int i = cmp.getInt("Type"); + + switch (i) { + case 1: + cmp.putString("id", "Donkey"); + break; + + case 2: + cmp.putString("id", "Mule"); + break; + + case 3: + cmp.putString("id", "ZombieHorse"); + break; + + case 4: + cmp.putString("id", "SkeletonHorse"); + break; + + case 0: + default: + cmp.putString("id", "Horse"); + break; + } + + cmp.remove("Type"); + } + + return cmp; + } + } + + private static class DataConverterTileEntity implements DataConverter { + + private static final Map a = Maps.newHashMap(); + + DataConverterTileEntity() { + } + + public int getDataVersion() { + return 704; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = DataConverterTileEntity.a.get(cmp.getString("id")); + + if (s != null) { + cmp.putString("id", s); + } + + return cmp; + } + + static { + DataConverterTileEntity.a.put("Airportal", "minecraft:end_portal"); + DataConverterTileEntity.a.put("Banner", "minecraft:banner"); + DataConverterTileEntity.a.put("Beacon", "minecraft:beacon"); + DataConverterTileEntity.a.put("Cauldron", "minecraft:brewing_stand"); + DataConverterTileEntity.a.put("Chest", "minecraft:chest"); + DataConverterTileEntity.a.put("Comparator", "minecraft:comparator"); + DataConverterTileEntity.a.put("Control", "minecraft:command_block"); + DataConverterTileEntity.a.put("DLDetector", "minecraft:daylight_detector"); + DataConverterTileEntity.a.put("Dropper", "minecraft:dropper"); + DataConverterTileEntity.a.put("EnchantTable", "minecraft:enchanting_table"); + DataConverterTileEntity.a.put("EndGateway", "minecraft:end_gateway"); + DataConverterTileEntity.a.put("EnderChest", "minecraft:ender_chest"); + DataConverterTileEntity.a.put("FlowerPot", "minecraft:flower_pot"); + DataConverterTileEntity.a.put("Furnace", "minecraft:furnace"); + DataConverterTileEntity.a.put("Hopper", "minecraft:hopper"); + DataConverterTileEntity.a.put("MobSpawner", "minecraft:mob_spawner"); + DataConverterTileEntity.a.put("Music", "minecraft:noteblock"); + DataConverterTileEntity.a.put("Piston", "minecraft:piston"); + DataConverterTileEntity.a.put("RecordPlayer", "minecraft:jukebox"); + DataConverterTileEntity.a.put("Sign", "minecraft:sign"); + DataConverterTileEntity.a.put("Skull", "minecraft:skull"); + DataConverterTileEntity.a.put("Structure", "minecraft:structure_block"); + DataConverterTileEntity.a.put("Trap", "minecraft:dispenser"); + } + } + + private static class DataConverterEntity implements DataConverter { + + private static final Map a = Maps.newHashMap(); + + DataConverterEntity() { + } + + public int getDataVersion() { + return 704; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = DataConverterEntity.a.get(cmp.getString("id")); + + if (s != null) { + cmp.putString("id", s); + } + + return cmp; + } + + static { + DataConverterEntity.a.put("AreaEffectCloud", "minecraft:area_effect_cloud"); + DataConverterEntity.a.put("ArmorStand", "minecraft:armor_stand"); + DataConverterEntity.a.put("Arrow", "minecraft:arrow"); + DataConverterEntity.a.put("Bat", "minecraft:bat"); + DataConverterEntity.a.put("Blaze", "minecraft:blaze"); + DataConverterEntity.a.put("Boat", "minecraft:boat"); + DataConverterEntity.a.put("CaveSpider", "minecraft:cave_spider"); + DataConverterEntity.a.put("Chicken", "minecraft:chicken"); + DataConverterEntity.a.put("Cow", "minecraft:cow"); + DataConverterEntity.a.put("Creeper", "minecraft:creeper"); + DataConverterEntity.a.put("Donkey", "minecraft:donkey"); + DataConverterEntity.a.put("DragonFireball", "minecraft:dragon_fireball"); + DataConverterEntity.a.put("ElderGuardian", "minecraft:elder_guardian"); + DataConverterEntity.a.put("EnderCrystal", "minecraft:ender_crystal"); + DataConverterEntity.a.put("EnderDragon", "minecraft:ender_dragon"); + DataConverterEntity.a.put("Enderman", "minecraft:enderman"); + DataConverterEntity.a.put("Endermite", "minecraft:endermite"); + DataConverterEntity.a.put("EyeOfEnderSignal", "minecraft:eye_of_ender_signal"); + DataConverterEntity.a.put("FallingSand", "minecraft:falling_block"); + DataConverterEntity.a.put("Fireball", "minecraft:fireball"); + DataConverterEntity.a.put("FireworksRocketEntity", "minecraft:fireworks_rocket"); + DataConverterEntity.a.put("Ghast", "minecraft:ghast"); + DataConverterEntity.a.put("Giant", "minecraft:giant"); + DataConverterEntity.a.put("Guardian", "minecraft:guardian"); + DataConverterEntity.a.put("Horse", "minecraft:horse"); + DataConverterEntity.a.put("Husk", "minecraft:husk"); + DataConverterEntity.a.put("Item", "minecraft:item"); + DataConverterEntity.a.put("ItemFrame", "minecraft:item_frame"); + DataConverterEntity.a.put("LavaSlime", "minecraft:magma_cube"); + DataConverterEntity.a.put("LeashKnot", "minecraft:leash_knot"); + DataConverterEntity.a.put("MinecartChest", "minecraft:chest_minecart"); + DataConverterEntity.a.put("MinecartCommandBlock", "minecraft:commandblock_minecart"); + DataConverterEntity.a.put("MinecartFurnace", "minecraft:furnace_minecart"); + DataConverterEntity.a.put("MinecartHopper", "minecraft:hopper_minecart"); + DataConverterEntity.a.put("MinecartRideable", "minecraft:minecart"); + DataConverterEntity.a.put("MinecartSpawner", "minecraft:spawner_minecart"); + DataConverterEntity.a.put("MinecartTNT", "minecraft:tnt_minecart"); + DataConverterEntity.a.put("Mule", "minecraft:mule"); + DataConverterEntity.a.put("MushroomCow", "minecraft:mooshroom"); + DataConverterEntity.a.put("Ozelot", "minecraft:ocelot"); + DataConverterEntity.a.put("Painting", "minecraft:painting"); + DataConverterEntity.a.put("Pig", "minecraft:pig"); + DataConverterEntity.a.put("PigZombie", "minecraft:zombie_pigman"); + DataConverterEntity.a.put("PolarBear", "minecraft:polar_bear"); + DataConverterEntity.a.put("PrimedTnt", "minecraft:tnt"); + DataConverterEntity.a.put("Rabbit", "minecraft:rabbit"); + DataConverterEntity.a.put("Sheep", "minecraft:sheep"); + DataConverterEntity.a.put("Shulker", "minecraft:shulker"); + DataConverterEntity.a.put("ShulkerBullet", "minecraft:shulker_bullet"); + DataConverterEntity.a.put("Silverfish", "minecraft:silverfish"); + DataConverterEntity.a.put("Skeleton", "minecraft:skeleton"); + DataConverterEntity.a.put("SkeletonHorse", "minecraft:skeleton_horse"); + DataConverterEntity.a.put("Slime", "minecraft:slime"); + DataConverterEntity.a.put("SmallFireball", "minecraft:small_fireball"); + DataConverterEntity.a.put("SnowMan", "minecraft:snowman"); + DataConverterEntity.a.put("Snowball", "minecraft:snowball"); + DataConverterEntity.a.put("SpectralArrow", "minecraft:spectral_arrow"); + DataConverterEntity.a.put("Spider", "minecraft:spider"); + DataConverterEntity.a.put("Squid", "minecraft:squid"); + DataConverterEntity.a.put("Stray", "minecraft:stray"); + DataConverterEntity.a.put("ThrownEgg", "minecraft:egg"); + DataConverterEntity.a.put("ThrownEnderpearl", "minecraft:ender_pearl"); + DataConverterEntity.a.put("ThrownExpBottle", "minecraft:xp_bottle"); + DataConverterEntity.a.put("ThrownPotion", "minecraft:potion"); + DataConverterEntity.a.put("Villager", "minecraft:villager"); + DataConverterEntity.a.put("VillagerGolem", "minecraft:villager_golem"); + DataConverterEntity.a.put("Witch", "minecraft:witch"); + DataConverterEntity.a.put("WitherBoss", "minecraft:wither"); + DataConverterEntity.a.put("WitherSkeleton", "minecraft:wither_skeleton"); + DataConverterEntity.a.put("WitherSkull", "minecraft:wither_skull"); + DataConverterEntity.a.put("Wolf", "minecraft:wolf"); + DataConverterEntity.a.put("XPOrb", "minecraft:xp_orb"); + DataConverterEntity.a.put("Zombie", "minecraft:zombie"); + DataConverterEntity.a.put("ZombieHorse", "minecraft:zombie_horse"); + DataConverterEntity.a.put("ZombieVillager", "minecraft:zombie_villager"); + } + } + + private static class DataConverterPotionWater implements DataConverter { + + DataConverterPotionWater() { + } + + public int getDataVersion() { + return 806; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = cmp.getString("id"); + + if ("minecraft:potion".equals(s) || "minecraft:splash_potion".equals(s) || "minecraft:lingering_potion".equals(s) || "minecraft:tipped_arrow".equals(s)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (!nbttagcompound1.contains("Potion", 8)) { + nbttagcompound1.putString("Potion", "minecraft:water"); + } + + if (!cmp.contains("tag", 10)) { + cmp.put("tag", nbttagcompound1); + } + } + + return cmp; + } + } + + private static class DataConverterShulker implements DataConverter { + + DataConverterShulker() { + } + + public int getDataVersion() { + return 808; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker".equals(cmp.getString("id")) && !cmp.contains("Color", 99)) { + cmp.putByte("Color", (byte) 10); + } + + return cmp; + } + } + + private static class DataConverterShulkerBoxItem implements DataConverter { + + public static final String[] a = 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" }; + + DataConverterShulkerBoxItem() { + } + + public int getDataVersion() { + return 813; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.getList("Items", 10).isEmpty()) { + nbttagcompound2.remove("Items"); + } + + int i = nbttagcompound2.getInt("Color"); + + nbttagcompound2.remove("Color"); + if (nbttagcompound2.isEmpty()) { + nbttagcompound1.remove("BlockEntityTag"); + } + + if (nbttagcompound1.isEmpty()) { + cmp.remove("tag"); + } + + cmp.putString("id", DataConverterShulkerBoxItem.a[i % 16]); + } + } + + return cmp; + } + } + + private static class DataConverterShulkerBoxBlock implements DataConverter { + + DataConverterShulkerBoxBlock() { + } + + public int getDataVersion() { + return 813; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker".equals(cmp.getString("id"))) { + cmp.remove("Color"); + } + + return cmp; + } + } + + private static class DataConverterLang implements DataConverter { + + DataConverterLang() { + } + + public int getDataVersion() { + return 816; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.contains("lang", 8)) { + cmp.putString("lang", cmp.getString("lang").toLowerCase(Locale.ROOT)); + } + + return cmp; + } + } + + private static class DataConverterTotem implements DataConverter { + + DataConverterTotem() { + } + + public int getDataVersion() { + return 820; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:totem".equals(cmp.getString("id"))) { + cmp.putString("id", "minecraft:totem_of_undying"); + } + + return cmp; + } + } + + private static class DataConverterBedBlock implements DataConverter { + + private static final Logger a = LogManager.getLogger(ForgeDataFixer.class); + + DataConverterBedBlock() { + } + + public int getDataVersion() { + return 1125; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + boolean flag = true; + + try { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + int i = nbttagcompound1.getInt("xPos"); + int j = nbttagcompound1.getInt("zPos"); + ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); + ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); + + for (int k = 0; k < nbttaglist1.size(); ++k) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist1.getCompound(k); + byte b0 = nbttagcompound2.getByte("Y"); + byte[] abyte = nbttagcompound2.getByteArray("Blocks"); + + for (int l = 0; l < abyte.length; ++l) { + if (416 == (abyte[l] & 255) << 4) { + int i1 = l & 15; + int j1 = l >> 8 & 15; + int k1 = l >> 4 & 15; + net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); + + nbttagcompound3.putString("id", "bed"); + nbttagcompound3.putInt("x", i1 + (i << 4)); + nbttagcompound3.putInt("y", j1 + (b0 << 4)); + nbttagcompound3.putInt("z", k1 + (j << 4)); + nbttaglist.add(nbttagcompound3); + } + } + } + } catch (Exception exception) { + DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); + } + + return cmp; + } + } + + private static class DataConverterBedItem implements DataConverter { + + DataConverterBedItem() { + } + + public int getDataVersion() { + return 1125; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { + cmp.putShort("Damage", (short) DyeColor.RED.getId()); + } + + return cmp; + } + } + + private static class DataConverterSignText implements DataConverter { + + public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { + MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + if (jsonelement.isJsonPrimitive()) { + return Component.literal(jsonelement.getAsString()); + } else if (jsonelement.isJsonArray()) { + JsonArray jsonarray = jsonelement.getAsJsonArray(); + MutableComponent iTextComponent = null; + Iterator iterator = jsonarray.iterator(); + + while (iterator.hasNext()) { + JsonElement jsonelement1 = (JsonElement) iterator.next(); + MutableComponent iTextComponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); + + if (iTextComponent == null) { + iTextComponent = iTextComponent1; + } else { + iTextComponent.append(iTextComponent1); + } + } + + return iTextComponent; + } else { + throw new JsonParseException("Don\'t know how to turn " + jsonelement + " into a Component"); + } + } + + public Object deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + return this.a(jsonelement, type, jsondeserializationcontext); + } + }).create(); + + DataConverterSignText() { + } + + public int getDataVersion() { + return 101; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Sign".equals(cmp.getString("id"))) { + this.convert(cmp, "Text1"); + this.convert(cmp, "Text2"); + this.convert(cmp, "Text3"); + this.convert(cmp, "Text4"); + } + + return cmp; + } + + private void convert(net.minecraft.nbt.CompoundTag nbttagcompound, String s) { + String s1 = nbttagcompound.getString(s); + Object object = null; + + if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { + if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { + object = Component.literal(s1); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); + if (object == null) { + object = Component.literal(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s1); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s1); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = Component.literal(s1); + } + } + } else { + object = Component.literal(""); + } + + nbttagcompound.putString(s, Component.Serializer.toJson((Component) object)); + } + } + + private static class DataInspectorPlayerVehicle implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("RootVehicle", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("RootVehicle"); + + if (nbttagcompound1.contains("Entity", 10)) { + convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); + } + } + + return cmp; + } + } + + private static class DataInspectorLevelPlayer implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Player", 10)) { + convertCompound(LegacyType.PLAYER, cmp, "Player", sourceVer, targetVer); + } + + return cmp; + } + } + + private static class DataInspectorStructure implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + ListTag nbttaglist; + int j; + net.minecraft.nbt.CompoundTag nbttagcompound1; + + if (cmp.contains("entities", 9)) { + nbttaglist = cmp.getList("entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (net.minecraft.nbt.CompoundTag) nbttaglist.get(j); + if (nbttagcompound1.contains("nbt", 10)) { + convertCompound(LegacyType.ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); + } + } + } + + if (cmp.contains("blocks", 9)) { + nbttaglist = cmp.getList("blocks", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (net.minecraft.nbt.CompoundTag) nbttaglist.get(j); + if (nbttagcompound1.contains("nbt", 10)) { + convertCompound(LegacyType.BLOCK_ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); + } + } + } + + return cmp; + } + } + + private static class DataInspectorChunks implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Level", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + ListTag nbttaglist; + int j; + + if (nbttagcompound1.contains("Entities", 9)) { + nbttaglist = nbttagcompound1.getList("Entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); + } + } + + if (nbttagcompound1.contains("TileEntities", 9)) { + nbttaglist = nbttagcompound1.getList("TileEntities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.BLOCK_ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); + } + } + } + + return cmp; + } + } + + private static class DataInspectorEntityPassengers implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Passengers", 9)) { + ListTag nbttaglist = cmp.getList("Passengers", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ENTITY, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } + + return cmp; + } + } + + private static class DataInspectorPlayer implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + convertItems(cmp, "Inventory", sourceVer, targetVer); + convertItems(cmp, "EnderItems", sourceVer, targetVer); + if (cmp.contains("ShoulderEntityLeft", 10)) { + convertCompound(LegacyType.ENTITY, cmp, "ShoulderEntityLeft", sourceVer, targetVer); + } + + if (cmp.contains("ShoulderEntityRight", 10)) { + convertCompound(LegacyType.ENTITY, cmp, "ShoulderEntityRight", sourceVer, targetVer); + } + + return cmp; + } + } + + private static class DataInspectorVillagers implements DataInspector { + ResourceLocation entityVillager = getKey("EntityVillager"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); + + if (nbttagcompound1.contains("Recipes", 9)) { + ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(j); + + convertItem(nbttagcompound2, "buy", sourceVer, targetVer); + convertItem(nbttagcompound2, "buyB", sourceVer, targetVer); + convertItem(nbttagcompound2, "sell", sourceVer, targetVer); + nbttaglist.set(j, nbttagcompound2); + } + } + } + + return cmp; + } + } + + private static class DataInspectorMobSpawnerMinecart implements DataInspector { + ResourceLocation entityMinecartMobSpawner = getKey("EntityMinecartMobSpawner"); + ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + String s = cmp.getString("id"); + if (entityMinecartMobSpawner.equals(new ResourceLocation(s))) { + cmp.putString("id", tileEntityMobSpawner.toString()); + convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); + cmp.putString("id", s); + } + + return cmp; + } + } + + private static class DataInspectorMobSpawnerMobs implements DataInspector { + ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { + if (cmp.contains("SpawnPotentials", 9)) { + ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = nbttaglist.getCompound(j); + + convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); + } + } + + convertCompound(LegacyType.ENTITY, cmp, "SpawnData", sourceVer, targetVer); + } + + return cmp; + } + } + + private static class DataInspectorCommandBlock implements DataInspector { + ResourceLocation tileEntityCommand = getKey("TileEntityCommand"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityCommand.equals(new ResourceLocation(cmp.getString("id")))) { + cmp.putString("id", "Control"); + convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); + cmp.putString("id", "MinecartCommandBlock"); + } + + return cmp; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java b/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java new file mode 100644 index 0000000..a5c1fab --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java @@ -0,0 +1,119 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.metadata.EntityProperties; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.forge.internal.NBTConverter; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.NullWorld; +import com.sk89q.worldedit.world.entity.EntityTypes; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; + +import java.lang.ref.WeakReference; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +class ForgeEntity implements Entity { + + private final WeakReference entityRef; + + ForgeEntity(net.minecraft.world.entity.Entity entity) { + checkNotNull(entity); + this.entityRef = new WeakReference<>(entity); + } + + @Override + public BaseEntity getState() { + net.minecraft.world.entity.Entity entity = entityRef.get(); + if (entity == null || entity.isPassenger()) { + return null; + } + ResourceLocation id = BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()); + if (id == null) { + return null; + } + CompoundTag tag = new CompoundTag(); + entity.saveWithoutId(tag); + return new BaseEntity(EntityTypes.get(id.toString()), NBTConverter.fromNative(tag)); + } + + @Override + public Location getLocation() { + net.minecraft.world.entity.Entity entity = entityRef.get(); + if (entity != null) { + Vector3 position = Vector3.at(entity.getX(), entity.getY(), entity.getZ()); + float yaw = entity.getYRot(); + float pitch = entity.getXRot(); + + return new Location(ForgeAdapter.adapt((ServerLevel) entity.level()), position, yaw, pitch); + } else { + return new Location(NullWorld.getInstance()); + } + } + + @Override + public boolean setLocation(Location location) { + // TODO unused atm + return false; + } + + @Override + public Extent getExtent() { + net.minecraft.world.entity.Entity entity = entityRef.get(); + if (entity != null) { + return ForgeAdapter.adapt((ServerLevel) entity.level()); + } else { + return NullWorld.getInstance(); + } + } + + @Override + public boolean remove() { + net.minecraft.world.entity.Entity entity = entityRef.get(); + if (entity != null) { + entity.remove(net.minecraft.world.entity.Entity.RemovalReason.KILLED); + } + return true; + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public T getFacet(Class cls) { + net.minecraft.world.entity.Entity entity = entityRef.get(); + if (entity != null) { + if (EntityProperties.class.isAssignableFrom(cls)) { + return (T) new ForgeEntityProperties(entity); + } else { + return null; + } + } else { + return null; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java b/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java new file mode 100644 index 0000000..5d2175e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java @@ -0,0 +1,156 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.entity.metadata.EntityProperties; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.ExperienceOrb; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.TamableAnimal; +import net.minecraft.world.entity.ambient.AmbientCreature; +import net.minecraft.world.entity.animal.AbstractGolem; +import net.minecraft.world.entity.animal.Animal; +import net.minecraft.world.entity.animal.WaterAnimal; +import net.minecraft.world.entity.boss.EnderDragonPart; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.decoration.ItemFrame; +import net.minecraft.world.entity.decoration.Painting; +import net.minecraft.world.entity.item.FallingBlockEntity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.item.PrimedTnt; +import net.minecraft.world.entity.npc.Npc; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraft.world.entity.vehicle.Boat; +import net.minecraft.world.item.trading.Merchant; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ForgeEntityProperties implements EntityProperties { + + private final Entity entity; + + public ForgeEntityProperties(Entity entity) { + checkNotNull(entity); + this.entity = entity; + } + + @Override + public boolean isPlayerDerived() { + return entity instanceof Player; + } + + @Override + public boolean isProjectile() { + return entity instanceof Projectile; + } + + @Override + public boolean isItem() { + return entity instanceof ItemEntity; + } + + @Override + public boolean isFallingBlock() { + return entity instanceof FallingBlockEntity; + } + + @Override + public boolean isPainting() { + return entity instanceof Painting; + } + + @Override + public boolean isItemFrame() { + return entity instanceof ItemFrame; + } + + @Override + public boolean isBoat() { + return entity instanceof Boat; + } + + @Override + public boolean isMinecart() { + return entity instanceof AbstractMinecart; + } + + @Override + public boolean isTNT() { + return entity instanceof PrimedTnt; + } + + @Override + public boolean isExperienceOrb() { + return entity instanceof ExperienceOrb; + } + + @Override + public boolean isLiving() { + return entity instanceof Mob; + } + + @Override + public boolean isAnimal() { + return entity instanceof Animal; + } + + @Override + public boolean isAmbient() { + return entity instanceof AmbientCreature; + } + + @Override + public boolean isNPC() { + return entity instanceof Npc || entity instanceof Merchant; + } + + @Override + public boolean isGolem() { + return entity instanceof AbstractGolem; + } + + @Override + public boolean isTamed() { + return entity instanceof TamableAnimal && ((TamableAnimal) entity).isTame(); + } + + @Override + public boolean isTagged() { + return entity.hasCustomName(); + } + + @Override + public boolean isArmorStand() { + return entity instanceof ArmorStand; + } + + @Override + public boolean isPasteable() { + return !(entity instanceof ServerPlayer || entity instanceof EnderDragonPart); + } + + @Override + public boolean isWaterCreature() { + return entity instanceof WaterAnimal; + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java b/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java new file mode 100644 index 0000000..fdf4db6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Streams; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; + +import java.util.Set; + +public class ForgeItemCategoryRegistry implements ItemCategoryRegistry { + @Override + public Set getCategorisedByName(String category) { + Iterable> tagged = BuiltInRegistries.ITEM.getTagOrEmpty(TagKey.create(Registries.ITEM, new ResourceLocation(category))); + + return Streams.stream(tagged) + .map(Holder::value) + .map(ForgeAdapter::adapt) + .collect(ImmutableSet.toImmutableSet()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java b/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java new file mode 100644 index 0000000..6c82184 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.blocks.BaseItemStack; +import net.kyori.text.Component; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.BundledItemRegistry; + +public class ForgeItemRegistry extends BundledItemRegistry { + + @Override + public Component getRichName(ItemType itemType) { + return TranslatableComponent.of( + ForgeAdapter.adapt(itemType).getDescriptionId() + ); + } + + @Override + public Component getRichName(BaseItemStack itemStack) { + return TranslatableComponent.of( + ForgeAdapter.adapt(itemStack).getDescriptionId() + ); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java b/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java new file mode 100644 index 0000000..68d17d1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java @@ -0,0 +1,66 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.GameType; +import net.neoforged.neoforge.server.ServerLifecycleHooks; + +public interface ForgePermissionsProvider { + + boolean hasPermission(ServerPlayer player, String permission); + + void registerPermission(String permission); + + class VanillaPermissionsProvider implements ForgePermissionsProvider { + + private final ForgePlatform platform; + + public VanillaPermissionsProvider(ForgePlatform platform) { + this.platform = platform; + } + + @Override + public boolean hasPermission(ServerPlayer player, String permission) { + ForgeConfiguration configuration = platform.getConfiguration(); + return configuration.cheatMode + || ServerLifecycleHooks.getCurrentServer().getPlayerList().isOp(player.getGameProfile()) + || (configuration.creativeEnable && player.gameMode.getGameModeForPlayer() == GameType.CREATIVE); + } + + @Override + public void registerPermission(String permission) { + } + } + + // TODO Re-add when Sponge for 1.14 is out + // class SpongePermissionsProvider implements ForgePermissionsProvider { + // + // @Override + // public boolean hasPermission(EntityPlayerMP player, String permission) { + // return ((Player) player).hasPermission(permission); + // } + // + // @Override + // public void registerPermission(ICommand command, String permission) { + // + // } + // } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java new file mode 100644 index 0000000..71bba37 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -0,0 +1,257 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.AbstractPlatform; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.MultiUserPlatform; +import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.forge.internal.ExtendedChunk; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.io.ResourceLoader; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.registry.Registries; +import net.minecraft.SharedConstants; +import net.minecraft.commands.Commands; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.players.PlayerList; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.storage.ServerLevelData; +import net.neoforged.neoforge.server.ServerLifecycleHooks; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nullable; + +import static java.util.stream.Collectors.toList; + +class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { + + private final ForgeWorldEdit mod; + private final ForgeDataFixer dataFixer; + private @Nullable ForgeWatchdog watchdog; + private boolean hookingEvents = false; + private final ResourceLoader resourceLoader = new ForgeResourceLoader(WorldEdit.getInstance()); + + ForgePlatform(ForgeWorldEdit mod) { + this.mod = mod; + this.dataFixer = new ForgeDataFixer(getDataVersion()); + } + + boolean isHookingEvents() { + return hookingEvents; + } + + @Override + public ResourceLoader getResourceLoader() { + return resourceLoader; + } + + @Override + public Registries getRegistries() { + return ForgeRegistries.getInstance(); + } + + @Override + public int getDataVersion() { + return SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + } + + @Override + public DataFixer getDataFixer() { + return dataFixer; + } + + @Override + public boolean isValidMobType(String type) { + return BuiltInRegistries.ENTITY_TYPE.containsKey(new ResourceLocation(type)); + } + + @Override + public void reload() { + getConfiguration().load(); + super.reload(); + } + + @Override + public int schedule(long delay, long period, Runnable task) { + return -1; + } + + @Override + @Nullable + public ForgeWatchdog getWatchdog() { + if (watchdog == null) { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server instanceof DedicatedServer) { + watchdog = new ForgeWatchdog((DedicatedServer) server); + } + } + return watchdog; + } + + @Override + public List getWorlds() { + Iterable worlds = ServerLifecycleHooks.getCurrentServer().getAllLevels(); + List ret = new ArrayList<>(); + for (ServerLevel world : worlds) { + ret.add(new ForgeWorld(world)); + } + return ret; + } + + @Nullable + @Override + public Player matchPlayer(Player player) { + if (player instanceof ForgePlayer) { + return player; + } else { + ServerPlayer entity = ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayerByName(player.getName()); + return entity != null ? new ForgePlayer(entity) : null; + } + } + + @Nullable + @Override + public World matchWorld(World world) { + if (world instanceof ForgeWorld) { + return world; + } else { + for (ServerLevel ws : ServerLifecycleHooks.getCurrentServer().getAllLevels()) { + if (((ServerLevelData) ws.getLevelData()).getLevelName().equals(world.getName())) { + return new ForgeWorld(ws); + } + } + + return null; + } + } + + @Override + public void registerCommands(CommandManager manager) { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server == null) { + return; + } + Commands mcMan = server.getCommands(); + + for (Command command : manager.getAllCommands().collect(toList())) { + CommandWrapper.register(mcMan.getDispatcher(), command); + Set perms = command.getCondition().as(PermissionCondition.class) + .map(PermissionCondition::getPermissions) + .orElseGet(Collections::emptySet); + if (!perms.isEmpty()) { + perms.forEach(ForgeWorldEdit.inst.getPermissionsProvider()::registerPermission); + } + } + } + + @Override + public void setGameHooksEnabled(boolean enabled) { + this.hookingEvents = enabled; + } + + @Override + public ForgeConfiguration getConfiguration() { + return mod.getConfig(); + } + + @Override + public String getVersion() { + return mod.getInternalVersion(); + } + + @Override + public String getPlatformName() { + return "Forge-Official"; + } + + @Override + public String getPlatformVersion() { + return mod.getInternalVersion(); + } + + @Override + public Map getCapabilities() { + Map capabilities = new EnumMap<>(Capability.class); + capabilities.put(Capability.CONFIGURATION, Preference.PREFER_OTHERS); + capabilities.put(Capability.WORLDEDIT_CUI, Preference.NORMAL); + capabilities.put(Capability.GAME_HOOKS, Preference.NORMAL); + capabilities.put(Capability.PERMISSIONS, Preference.NORMAL); + capabilities.put(Capability.USER_COMMANDS, Preference.NORMAL); + capabilities.put(Capability.WORLD_EDITING, Preference.PREFERRED); + return capabilities; + } + + private static final Set SUPPORTED_SIDE_EFFECTS_NO_MIXIN = Sets.immutableEnumSet( + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.LIGHTING, + SideEffect.NEIGHBORS, + SideEffect.EVENTS + ); + + private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + Iterables.concat(SUPPORTED_SIDE_EFFECTS_NO_MIXIN, Collections.singleton(SideEffect.UPDATE)) + ); + + @Override + public Set getSupportedSideEffects() { + return ExtendedChunk.class.isAssignableFrom(LevelChunk.class) + ? SUPPORTED_SIDE_EFFECTS + : SUPPORTED_SIDE_EFFECTS_NO_MIXIN; + } + + @Override + public long getTickCount() { + return ServerLifecycleHooks.getCurrentServer().getTickCount(); + } + + @Override + public Collection getConnectedUsers() { + List users = new ArrayList<>(); + PlayerList scm = ServerLifecycleHooks.getCurrentServer().getPlayerList(); + for (ServerPlayer entity : scm.getPlayers()) { + if (entity != null) { + users.add(new ForgePlayer(entity)); + } + } + return users; + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java new file mode 100644 index 0000000..41dc8a2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -0,0 +1,299 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.platform.AbstractPlayerActor; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.forge.internal.NBTConverter; +import com.sk89q.worldedit.forge.net.handler.WECUIPacketHandler; +import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.session.SessionKey; +import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.WorldEditText; +import com.sk89q.worldedit.util.formatting.component.TextUtils; +import net.kyori.text.Component; +import net.kyori.text.serializer.gson.GsonComponentSerializer; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; +import io.netty.buffer.Unpooled; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; + +import java.nio.charset.StandardCharsets; +import java.util.Locale; +import java.util.UUID; +import javax.annotation.Nullable; + +public class ForgePlayer extends AbstractPlayerActor { + + private final ServerPlayer player; + + protected ForgePlayer(ServerPlayer player) { + this.player = player; + ThreadSafeCache.getInstance().getOnlineIds().add(getUniqueId()); + } + + @Override + public UUID getUniqueId() { + return player.getUUID(); + } + + @Override + public BaseItemStack getItemInHand(HandSide handSide) { + ItemStack is = this.player.getItemInHand( + handSide == HandSide.MAIN_HAND + ? InteractionHand.MAIN_HAND + : InteractionHand.OFF_HAND + ); + return ForgeAdapter.adapt(is); + } + + @Override + public String getName() { + return this.player.getName().getString(); + } + + @Override + public BaseEntity getState() { + throw new UnsupportedOperationException("Cannot create a state from this object"); + } + + @Override + public Location getLocation() { + Vector3 position = Vector3.at(this.player.getX(), this.player.getY(), this.player.getZ()); + return new Location( + ForgeWorldEdit.inst.getWorld(this.player.serverLevel()), + position, + this.player.getYRot(), + this.player.getXRot()); + } + + @Override + public boolean setLocation(Location location) { + ServerLevel level = ForgeAdapter.adapt((World) location.getExtent()); + this.player.teleportTo( + level, + location.getX(), location.getY(), location.getZ(), + location.getYaw(), location.getPitch() + ); + // This may be false if the teleport was cancelled by a mod + return this.player.serverLevel() == level; + } + + @Override + public World getWorld() { + return ForgeWorldEdit.inst.getWorld(this.player.serverLevel()); + } + + @Override + public void giveItem(BaseItemStack itemStack) { + this.player.getInventory().add(ForgeAdapter.adapt(itemStack)); + } + + @Override + public void dispatchCUIEvent(CUIEvent event) { + String[] params = event.getParameters(); + String send = event.getTypeId(); + if (params.length > 0) { + send = send + "|" + StringUtil.joinString(params, "|"); + } + FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.copiedBuffer(send, StandardCharsets.UTF_8)); + WECUIPacketHandler.send(this.player.connection.connection, buffer); + } + + private void sendMessage(net.minecraft.network.chat.Component textComponent) { + this.player.sendSystemMessage(textComponent); + } + + @Override + @Deprecated + public void printRaw(String msg) { + for (String part : msg.split("\n")) { + sendMessage(net.minecraft.network.chat.Component.literal(part)); + } + } + + @Override + @Deprecated + public void printDebug(String msg) { + sendColorized(msg, ChatFormatting.GRAY); + } + + @Override + @Deprecated + public void print(String msg) { + sendColorized(msg, ChatFormatting.LIGHT_PURPLE); + } + + @Override + @Deprecated + public void printError(String msg) { + sendColorized(msg, ChatFormatting.RED); + } + + @Override + public void print(Component component) { + sendMessage(net.minecraft.network.chat.Component.Serializer.fromJson( + GsonComponentSerializer.INSTANCE.serialize(WorldEditText.format(component, getLocale())) + )); + } + + private void sendColorized(String msg, ChatFormatting formatting) { + for (String part : msg.split("\n")) { + var component = net.minecraft.network.chat.Component.literal(part); + component.withStyle(formatting); + sendMessage(component); + } + } + + @Override + public boolean trySetPosition(Vector3 pos, float pitch, float yaw) { + this.player.connection.teleport(pos.getX(), pos.getY(), pos.getZ(), yaw, pitch); + return true; + } + + @Override + public String[] getGroups() { + return new String[] {}; // WorldEditMod.inst.getPermissionsResolver().getGroups(this.player.username); + } + + @Override + public BlockBag getInventoryBlockBag() { + return null; + } + + @Override + public boolean hasPermission(String perm) { + return ForgeWorldEdit.inst.getPermissionsProvider().hasPermission(player, perm); + } + + @Nullable + @Override + public T getFacet(Class cls) { + return null; + } + + @Override + public boolean isAllowedToFly() { + return player.getAbilities().mayfly; + } + + @Override + public void setFlying(boolean flying) { + if (player.getAbilities().flying != flying) { + player.getAbilities().flying = flying; + player.onUpdateAbilities(); + } + } + + @Override + public Locale getLocale() { + return TextUtils.getLocaleByMinecraftTag(player.getLanguage()); + } + + @Override + public > void sendFakeBlock(BlockVector3 pos, B block) { + World world = getWorld(); + if (!(world instanceof ForgeWorld)) { + return; + } + BlockPos loc = ForgeAdapter.toBlockPos(pos); + if (block == null) { + final ClientboundBlockUpdatePacket packetOut = new ClientboundBlockUpdatePacket( + ((ForgeWorld) world).getWorld(), + loc + ); + player.connection.send(packetOut); + } else { + player.connection.send(new ClientboundBlockUpdatePacket( + loc, ForgeAdapter.adapt(block.toImmutableState()) + )); + if (block instanceof BaseBlock baseBlock && block.getBlockType().equals(BlockTypes.STRUCTURE_BLOCK)) { + final CompoundTag nbtData = baseBlock.getNbtData(); + if (nbtData != null) { + player.connection.send(new ClientboundBlockEntityDataPacket( + new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), + BlockEntityType.STRUCTURE_BLOCK, + NBTConverter.toNative(nbtData) + )); + } + } + } + } + + @Override + public SessionKey getSessionKey() { + return new SessionKeyImpl(player); + } + + static class SessionKeyImpl implements SessionKey { + // If not static, this will leak a reference + + private final UUID uuid; + private final String name; + + SessionKeyImpl(ServerPlayer player) { + this.uuid = player.getUUID(); + this.name = player.getName().getString(); + } + + @Override + public UUID getUniqueId() { + return uuid; + } + + @Nullable + @Override + public String getName() { + return name; + } + + @Override + public boolean isActive() { + // We can't directly check if the player is online because + // the list of players is not thread safe + return ThreadSafeCache.getInstance().getOnlineIds().contains(uuid); + } + + @Override + public boolean isPersistent() { + return true; + } + + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeRegistries.java b/src/main/java/com/sk89q/worldedit/forge/ForgeRegistries.java new file mode 100644 index 0000000..55d77ab --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeRegistries.java @@ -0,0 +1,75 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; +import com.sk89q.worldedit.world.registry.BlockRegistry; +import com.sk89q.worldedit.world.registry.BundledRegistries; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; +import com.sk89q.worldedit.world.registry.ItemRegistry; + +/** + * World data for the Forge platform. + */ +class ForgeRegistries extends BundledRegistries { + + private static final ForgeRegistries INSTANCE = new ForgeRegistries(); + private final BlockRegistry blockRegistry = new ForgeBlockRegistry(); + private final BiomeRegistry biomeRegistry = new ForgeBiomeRegistry(); + private final ItemRegistry itemRegistry = new ForgeItemRegistry(); + private final BlockCategoryRegistry blockCategoryRegistry = new ForgeBlockCategoryRegistry(); + private final ItemCategoryRegistry itemCategoryRegistry = new ForgeItemCategoryRegistry(); + + @Override + public BlockRegistry getBlockRegistry() { + return blockRegistry; + } + + @Override + public BiomeRegistry getBiomeRegistry() { + return biomeRegistry; + } + + @Override + public ItemRegistry getItemRegistry() { + return itemRegistry; + } + + @Override + public BlockCategoryRegistry getBlockCategoryRegistry() { + return blockCategoryRegistry; + } + + @Override + public ItemCategoryRegistry getItemCategoryRegistry() { + return itemCategoryRegistry; + } + + /** + * Get a static instance. + * + * @return an instance + */ + public static ForgeRegistries getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeResourceLoader.java b/src/main/java/com/sk89q/worldedit/forge/ForgeResourceLoader.java new file mode 100644 index 0000000..043ffb2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeResourceLoader.java @@ -0,0 +1,58 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.util.io.WorldEditResourceLoader; + +import java.io.IOException; +import java.net.URL; + +public class ForgeResourceLoader extends WorldEditResourceLoader { + + public ForgeResourceLoader(WorldEdit worldEdit) { + super(worldEdit); + } + + private static URL getResourceForgeHack(String location) throws IOException { + try { + URL url = new URL("modjar://worldedit/" + location); + try { + url.openStream(); + } catch (IOException e) { + // doesn't actually exist + return null; + } + return url; + } catch (Exception e) { + throw new IOException("Could not find " + location); + } + } + + @Override + public URL getRootResource(String pathName) throws IOException { + URL url = super.getRootResource(pathName); + if (url == null) { + return getResourceForgeHack(pathName); + } + return url; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.java b/src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.java new file mode 100644 index 0000000..5cf43d0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.java @@ -0,0 +1,38 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.sk89q.worldedit.extension.platform.Watchdog; +import net.minecraft.Util; +import net.minecraft.server.dedicated.DedicatedServer; + +class ForgeWatchdog implements Watchdog { + + private final DedicatedServer server; + + ForgeWatchdog(DedicatedServer server) { + this.server = server; + } + + @Override + public void tick() { + server.nextTickTimeNanos = Util.getNanos(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java new file mode 100644 index 0000000..d478503 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -0,0 +1,679 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import com.google.common.collect.Streams; +import com.google.common.util.concurrent.Futures; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTConstants; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.forge.internal.ForgeWorldNativeAccess; +import com.sk89q.worldedit.forge.internal.NBTConverter; +import com.sk89q.worldedit.forge.internal.TileEntityUtils; +import com.sk89q.worldedit.function.mask.AbstractExtentMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Mask2D; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.TreeGenerator.TreeType; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.world.AbstractWorld; +import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.item.ItemTypes; +import com.sk89q.worldedit.world.weather.WeatherType; +import com.sk89q.worldedit.world.weather.WeatherTypes; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; +import net.minecraft.data.worldgen.features.EndFeatures; +import net.minecraft.data.worldgen.features.TreeFeatures; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.util.thread.BlockableEventLoop; +import net.minecraft.world.Clearable; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.storage.LevelData; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import net.minecraft.world.level.storage.ServerLevelData; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; + +import java.lang.ref.WeakReference; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalLong; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ThreadLocalRandom; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +/** + * An adapter to Minecraft worlds for WorldEdit. + */ +public class ForgeWorld extends AbstractWorld { + + private static final RandomSource random = RandomSource.create(); + + private static ResourceLocation getDimensionRegistryKey(ServerLevel world) { + return Objects.requireNonNull(world.getServer(), "server cannot be null") + .registryAccess() + .registryOrThrow(Registries.DIMENSION_TYPE) + .getKey(world.dimensionType()); + } + + private final WeakReference worldRef; + private final ForgeWorldNativeAccess nativeAccess; + + /** + * Construct a new world. + * + * @param world the world + */ + ForgeWorld(ServerLevel world) { + checkNotNull(world); + this.worldRef = new WeakReference<>(world); + this.nativeAccess = new ForgeWorldNativeAccess(worldRef); + } + + /** + * Get the underlying handle to the world. + * + * @return the world + * @throws RuntimeException thrown if a reference to the world was lost (i.e. world was unloaded) + */ + public ServerLevel getWorld() { + ServerLevel world = worldRef.get(); + if (world != null) { + return world; + } else { + throw new RuntimeException("The reference to the world was lost (i.e. the world may have been unloaded)"); + } + } + + @Override + public String getName() { + return ((ServerLevelData) getWorld().getLevelData()).getLevelName(); + } + + @Override + public String getId() { + return getName() + "_" + getDimensionRegistryKey(getWorld()); + } + + @Override + public Path getStoragePath() { + final ServerLevel world = getWorld(); + return world.getServer().storageSource.getDimensionPath(world.dimension()); + } + + @Override + public > boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException { + clearContainerBlockContents(position); + return nativeAccess.setBlock(position, block, sideEffects); + } + + @Override + public Set applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) { + nativeAccess.applySideEffects(position, previousType, sideEffectSet); + return Sets.intersection(ForgeWorldEdit.inst.getPlatform().getSupportedSideEffects(), sideEffectSet.getSideEffectsToApply()); + } + + @Override + public int getBlockLightLevel(BlockVector3 position) { + checkNotNull(position); + return getWorld().getLightEmission(ForgeAdapter.toBlockPos(position)); + } + + @Override + public boolean clearContainerBlockContents(BlockVector3 position) { + checkNotNull(position); + + BlockEntity tile = getWorld().getBlockEntity(ForgeAdapter.toBlockPos(position)); + if (tile instanceof Clearable) { + ((Clearable) tile).clearContent(); + return true; + } + return false; + } + + @Override + public BiomeType getBiome(BlockVector3 position) { + checkNotNull(position); + + LevelChunk chunk = getWorld().getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4); + return getBiomeInChunk(position, chunk); + } + + private BiomeType getBiomeInChunk(BlockVector3 position, ChunkAccess chunk) { + return ForgeAdapter.adapt( + chunk.getNoiseBiome(position.getX() >> 2, position.getY() >> 2, position.getZ() >> 2).value() + ); + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + checkNotNull(position); + checkNotNull(biome); + + LevelChunk chunk = getWorld().getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4); + var biomes = (PalettedContainer>) chunk.getSection(chunk.getSectionIndex(position.getY())).getBiomes(); + biomes.getAndSetUnchecked( + position.getX() & 3, position.getY() & 3, position.getZ() & 3, + getWorld().registryAccess().registry(Registries.BIOME) + .orElseThrow() + .getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(biome.getId()))) + ); + chunk.setUnsaved(true); + return true; + } + + private static final LoadingCache fakePlayers + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(WorldEditFakePlayer::new)); + + @Override + public boolean useItem(BlockVector3 position, BaseItem item, Direction face) { + ItemStack stack = ForgeAdapter.adapt(new BaseItemStack(item.getType(), item.getNbtData(), 1)); + ServerLevel world = getWorld(); + final WorldEditFakePlayer fakePlayer; + try { + fakePlayer = fakePlayers.get(world); + } catch (ExecutionException ignored) { + return false; + } + fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); + fakePlayer.absMoveTo(position.getBlockX(), position.getBlockY(), position.getBlockZ(), + (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); + final BlockPos blockPos = ForgeAdapter.toBlockPos(position); + final BlockHitResult rayTraceResult = new BlockHitResult(ForgeAdapter.toVec3(position), + ForgeAdapter.adapt(face), blockPos, false); + UseOnContext itemUseContext = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTraceResult); + InteractionResult used = stack.onItemUseFirst(itemUseContext); + if (used != InteractionResult.SUCCESS) { + // try activating the block + InteractionResult resultType = getWorld().getBlockState(blockPos) + .use(world, fakePlayer, InteractionHand.MAIN_HAND, rayTraceResult); + if (resultType.consumesAction()) { + used = resultType; + } else { + used = stack.getItem().use(world, fakePlayer, InteractionHand.MAIN_HAND).getResult(); + } + } + return used == InteractionResult.SUCCESS; + } + + @Override + public void dropItem(Vector3 position, BaseItemStack item) { + checkNotNull(position); + checkNotNull(item); + + if (item.getType() == ItemTypes.AIR) { + return; + } + + ItemEntity entity = new ItemEntity(getWorld(), position.getX(), position.getY(), position.getZ(), ForgeAdapter.adapt(item)); + entity.setPickUpDelay(10); + getWorld().addFreshEntity(entity); + } + + @Override + public void simulateBlockMine(BlockVector3 position) { + BlockPos pos = ForgeAdapter.toBlockPos(position); + getWorld().destroyBlock(pos, true); + } + + @Override + public boolean canPlaceAt(BlockVector3 position, BlockState blockState) { + return ForgeAdapter.adapt(blockState).canSurvive(getWorld(), ForgeAdapter.toBlockPos(position)); + } + + // For unmapped regen names, see Fabric! + + @Override + public boolean regenerate(Region region, Extent extent, RegenOptions options) { + try { + doRegen(region, extent, options); + } catch (Exception e) { + throw new IllegalStateException("Regen failed", e); + } + + return true; + } + + private void doRegen(Region region, Extent extent, RegenOptions options) throws Exception { + Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); + LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); + try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("WorldEditTempGen")) { + ServerLevel originalWorld = getWorld(); + PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() + .getWorldData().overworldData(); + WorldOptions originalOpts = levelProperties.worldGenOptions(); + + long seed = options.getSeed().orElse(originalWorld.getSeed()); + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) + : originalOpts; + + levelProperties.worldOptions = newOpts; + ResourceKey worldRegKey = originalWorld.dimension(); + try (ServerLevel serverWorld = new ServerLevel( + originalWorld.getServer(), Util.backgroundExecutor(), session, + ((ServerLevelData) originalWorld.getLevelData()), + worldRegKey, + new LevelStem( + originalWorld.dimensionTypeRegistration(), + originalWorld.getChunkSource().getGenerator() + ), + new WorldEditGenListener(), + originalWorld.isDebug(), + seed, + // No spawners are needed for this world. + ImmutableList.of(), + // This controls ticking, we don't need it so set it to false. + false, + originalWorld.getRandomSequences() + )) { + regenForWorld(region, extent, serverWorld, options); + + // drive the server executor until all tasks are popped off + while (originalWorld.getServer().pollTask()) { + Thread.yield(); + } + } finally { + levelProperties.worldOptions = originalOpts; + } + } finally { + SafeFiles.tryHardToDeleteDir(tempDir); + } + } + + private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, + RegenOptions options) throws WorldEditException { + List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); + + // drive executor until loading finishes + BlockableEventLoop executor = serverWorld.getChunkSource().mainThreadProcessor; + executor.managedBlock(() -> { + // bail out early if a future fails + if (chunkLoadings.stream().anyMatch(ftr -> + ftr.isDone() && Futures.getUnchecked(ftr) == null + )) { + return false; + } + return chunkLoadings.stream().allMatch(CompletableFuture::isDone); + }); + + Map chunks = new HashMap<>(); + for (CompletableFuture future : chunkLoadings) { + @Nullable + ChunkAccess chunk = future.getNow(null); + checkState(chunk != null, "Failed to generate a chunk, regen failed."); + chunks.put(chunk.getPos(), chunk); + } + + for (BlockVector3 vec : region) { + BlockPos pos = ForgeAdapter.toBlockPos(vec); + ChunkAccess chunk = chunks.get(new ChunkPos(pos)); + BlockStateHolder state = ForgeAdapter.adapt(chunk.getBlockState(pos)); + BlockEntity blockEntity = chunk.getBlockEntity(pos); + if (blockEntity != null) { + state = state.toBaseBlock(NBTConverter.fromNative(blockEntity.saveWithFullMetadata())); + } + extent.setBlock(vec, state.toBaseBlock()); + + if (options.shouldRegenBiomes()) { + BiomeType biome = getBiomeInChunk(vec, chunk); + extent.setBiome(vec, biome); + } + } + } + + private List> submitChunkLoadTasks(Region region, ServerLevel world) { + List> chunkLoadings = new ArrayList<>(); + // Pre-gen all the chunks + for (BlockVector2 chunk : region.getChunks()) { + chunkLoadings.add( + world.getChunkSource().getChunkFutureMainThread(chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true) + .thenApply(either -> either.left().orElse(null)) + ); + } + return chunkLoadings; + } + + @Nullable + private static ResourceKey> createTreeFeatureGenerator(TreeType type) { + return switch (type) { + case TREE -> TreeFeatures.OAK; + case BIG_TREE -> TreeFeatures.FANCY_OAK; + case REDWOOD -> TreeFeatures.SPRUCE; + case TALL_REDWOOD -> TreeFeatures.MEGA_SPRUCE; + case MEGA_REDWOOD -> TreeFeatures.MEGA_PINE; + case BIRCH -> TreeFeatures.BIRCH; + case JUNGLE -> TreeFeatures.MEGA_JUNGLE_TREE; + case SMALL_JUNGLE -> TreeFeatures.JUNGLE_TREE; + case SHORT_JUNGLE -> TreeFeatures.JUNGLE_TREE_NO_VINE; + case JUNGLE_BUSH -> TreeFeatures.JUNGLE_BUSH; + case SWAMP -> TreeFeatures.SWAMP_OAK; + case ACACIA -> TreeFeatures.ACACIA; + case DARK_OAK -> TreeFeatures.DARK_OAK; + case TALL_BIRCH -> TreeFeatures.SUPER_BIRCH_BEES_0002; + case RED_MUSHROOM -> TreeFeatures.HUGE_RED_MUSHROOM; + case BROWN_MUSHROOM -> TreeFeatures.HUGE_BROWN_MUSHROOM; + case WARPED_FUNGUS -> TreeFeatures.WARPED_FUNGUS; + case CRIMSON_FUNGUS -> TreeFeatures.CRIMSON_FUNGUS; + case CHORUS_PLANT -> EndFeatures.CHORUS_PLANT; + case MANGROVE -> TreeFeatures.MANGROVE; + case TALL_MANGROVE -> TreeFeatures.TALL_MANGROVE; + case CHERRY -> TreeFeatures.CHERRY; + case RANDOM -> createTreeFeatureGenerator(TreeType.values()[ThreadLocalRandom.current().nextInt(TreeType.values().length)]); + default -> null; + }; + } + + @Override + public boolean generateTree(TreeType type, EditSession editSession, BlockVector3 position) { + ServerLevel world = getWorld(); + ConfiguredFeature generator = Optional.ofNullable(createTreeFeatureGenerator(type)) + .map(k -> world.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(k)) + .orElse(null); + ServerChunkCache chunkManager = world.getChunkSource(); + if (type == TreeType.CHORUS_PLANT) { + position = position.add(0, 1, 0); + } + return generator != null && generator.place( + world, chunkManager.getGenerator(), random, ForgeAdapter.toBlockPos(position) + ); + } + + @Override + public void checkLoadedChunk(BlockVector3 pt) { + getWorld().getChunk(ForgeAdapter.toBlockPos(pt)); + } + + @Override + public void fixAfterFastMode(Iterable chunks) { + fixLighting(chunks); + } + + @Override + public void fixLighting(Iterable chunks) { + ServerLevel world = getWorld(); + for (BlockVector2 chunk : chunks) { + // Fetch the chunk after light initialization at least + // We'll be doing a full relight anyways, so we don't need to be LIGHT yet + world.getChunkSource().getLightEngine().lightChunk(world.getChunk( + chunk.getBlockX(), chunk.getBlockZ(), ChunkStatus.INITIALIZE_LIGHT + ), false); + } + } + + @Override + public boolean playEffect(Vector3 position, int type, int data) { + // TODO update sound API + // getWorld().play(type, ForgeAdapter.toBlockPos(position.toBlockPoint()), data); + return true; + } + + @Override + public WeatherType getWeather() { + LevelData info = getWorld().getLevelData(); + if (info.isThundering()) { + return WeatherTypes.THUNDER_STORM; + } + if (info.isRaining()) { + return WeatherTypes.RAIN; + } + return WeatherTypes.CLEAR; + } + + @Override + public long getRemainingWeatherDuration() { + ServerLevelData info = (ServerLevelData) getWorld().getLevelData(); + if (info.isThundering()) { + return info.getThunderTime(); + } + if (info.isRaining()) { + return info.getRainTime(); + } + return info.getClearWeatherTime(); + } + + @Override + public void setWeather(WeatherType weatherType) { + setWeather(weatherType, 0); + } + + @Override + public void setWeather(WeatherType weatherType, long duration) { + ServerLevelData info = (ServerLevelData) getWorld().getLevelData(); + if (weatherType == WeatherTypes.THUNDER_STORM) { + info.setClearWeatherTime(0); + info.setThundering(true); + info.setThunderTime((int) duration); + } else if (weatherType == WeatherTypes.RAIN) { + info.setClearWeatherTime(0); + info.setRaining(true); + info.setRainTime((int) duration); + } else if (weatherType == WeatherTypes.CLEAR) { + info.setRaining(false); + info.setThundering(false); + info.setClearWeatherTime((int) duration); + } + } + + @Override + public int getMinY() { + return getWorld().getMinBuildHeight(); + } + + @Override + public int getMaxY() { + return getWorld().getMaxBuildHeight() - 1; + } + + @Override + public BlockVector3 getSpawnPosition() { + LevelData worldInfo = getWorld().getLevelData(); + return BlockVector3.at( + worldInfo.getXSpawn(), + worldInfo.getYSpawn(), + worldInfo.getZSpawn() + ); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + net.minecraft.world.level.block.state.BlockState mcState = getWorld() + .getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4) + .getBlockState(ForgeAdapter.toBlockPos(position)); + + return ForgeAdapter.adapt(mcState); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + BlockEntity tile = getWorld().getChunk(pos).getBlockEntity(pos); + + if (tile != null) { + return getBlock(position).toBaseBlock(NBTConverter.fromNative(TileEntityUtils.copyNbtData(tile))); + } else { + return getBlock(position).toBaseBlock(); + } + } + + @Override + public int hashCode() { + return getWorld().hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } else if ((o instanceof ForgeWorld other)) { + Level otherWorld = other.worldRef.get(); + Level thisWorld = worldRef.get(); + return otherWorld != null && otherWorld.equals(thisWorld); + } else if (o instanceof com.sk89q.worldedit.world.World) { + return ((com.sk89q.worldedit.world.World) o).getName().equals(getName()); + } else { + return false; + } + } + + @Override + public List getEntities(Region region) { + final ServerLevel world = getWorld(); + AABB box = new AABB( + Vec3.atBottomCenterOf(ForgeAdapter.toBlockPos(region.getMinimumPoint())), + Vec3.atBottomCenterOf(ForgeAdapter.toBlockPos(region.getMaximumPoint().add(BlockVector3.ONE))) + ); + List nmsEntities = world.getEntities( + (net.minecraft.world.entity.Entity) null, + box, + e -> region.contains(ForgeAdapter.adapt(e.blockPosition())) + ); + return nmsEntities.stream().map(ForgeEntity::new).collect(ImmutableList.toImmutableList()); + } + + @Override + public List getEntities() { + final ServerLevel world = getWorld(); + return Streams.stream(world.getAllEntities()) + .map(ForgeEntity::new) + .collect(ImmutableList.toImmutableList()); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + ServerLevel world = getWorld(); + String entityId = entity.getType().getId(); + final Optional> entityType = EntityType.byString(entityId); + if (entityType.isEmpty()) { + return null; + } + CompoundTag nativeTag = entity.getNbtData(); + net.minecraft.nbt.CompoundTag tag; + if (nativeTag != null) { + tag = NBTConverter.toNative(entity.getNbtData()); + removeUnwantedEntityTagsRecursively(tag); + } else { + tag = new net.minecraft.nbt.CompoundTag(); + } + tag.putString("id", entityId); + + net.minecraft.world.entity.Entity createdEntity = EntityType.loadEntityRecursive(tag, world, (loadedEntity) -> { + loadedEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + return loadedEntity; + }); + if (createdEntity != null) { + world.addFreshEntityWithPassengers(createdEntity); + return new ForgeEntity(createdEntity); + } + return null; + } + + private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + + // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive + if (tag.contains("Passengers", NBTConstants.TYPE_LIST)) { + net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", NBTConstants.TYPE_COMPOUND); + + for (int i = 0; i < nbttaglist.size(); ++i) { + removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); + } + } + } + + @Override + public Mask createLiquidMask() { + return new AbstractExtentMask(this) { + @Override + public boolean test(BlockVector3 vector) { + return ForgeAdapter.adapt(getExtent().getBlock(vector)).getBlock() instanceof LiquidBlock; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java new file mode 100644 index 0000000..10684db --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -0,0 +1,452 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.event.platform.PlatformReadyEvent; +import com.sk89q.worldedit.event.platform.PlatformUnreadyEvent; +import com.sk89q.worldedit.event.platform.PlatformsRegisteredEvent; +import com.sk89q.worldedit.event.platform.SessionIdleEvent; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.PlatformManager; +import com.sk89q.worldedit.forge.net.handler.WECUIPacketHandler; +import com.sk89q.worldedit.internal.anvil.ChunkDeleter; +import com.sk89q.worldedit.internal.event.InteractionDebouncer; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.item.ItemCategory; +import com.sk89q.worldedit.world.item.ItemType; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.tags.TagKey; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.neoforged.bus.api.Event; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.IExtensionPoint; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.fml.javafmlmod.FMLJavaModLoadingContext; +import net.neoforged.fml.loading.FMLPaths; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.CommandEvent; +import net.neoforged.neoforge.event.RegisterCommandsEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; +import net.neoforged.neoforge.event.server.ServerAboutToStartEvent; +import net.neoforged.neoforge.event.server.ServerStartedEvent; +import net.neoforged.neoforge.event.server.ServerStoppingEvent; +import org.apache.logging.log4j.Logger; +import org.enginehub.piston.Command; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.forge.ForgeAdapter.adaptCommandSource; +import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; +import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; + +/** + * The Forge implementation of WorldEdit. + */ +@Mod(ForgeWorldEdit.MOD_ID) +public class ForgeWorldEdit { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + public static final String MOD_ID = "worldedit"; + public static final String CUI_PLUGIN_CHANNEL = "cui"; + + private ForgePermissionsProvider provider; + + public static ForgeWorldEdit inst; + + private InteractionDebouncer debouncer; + private ForgePlatform platform; + private ForgeConfiguration config; + private Path workingDir; + + private ModContainer container; + + public ForgeWorldEdit() { + inst = this; + + IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); + modBus.addListener(this::init); + + NeoForge.EVENT_BUS.register(ThreadSafeCache.getInstance()); + NeoForge.EVENT_BUS.register(this); + + // Mark WorldEdit as only required on the server + try { + // TODO compile under --release 16 and call this normally in 7.3.0 + ModLoadingContext.class.getDeclaredMethod("registerExtensionPoint", Class.class, Supplier.class) + .invoke( + ModLoadingContext.get(), + IExtensionPoint.DisplayTest.class, + (Supplier) () -> new IExtensionPoint.DisplayTest( + () -> IExtensionPoint.DisplayTest.IGNORESERVERONLY, + (a, b) -> true + ) + ); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new IllegalStateException(e); + } + } + + private void init(FMLCommonSetupEvent event) { + this.container = ModLoadingContext.get().getActiveContainer(); + + // Setup working directory + workingDir = FMLPaths.CONFIGDIR.get().resolve("worldedit"); + if (!Files.exists(workingDir)) { + try { + Files.createDirectory(workingDir); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + setupPlatform(); + + WECUIPacketHandler.init(); + + LOGGER.info("WorldEdit for Forge (version " + getInternalVersion() + ") is loaded"); + } + + private void setupPlatform() { + this.platform = new ForgePlatform(this); + debouncer = new InteractionDebouncer(platform); + + WorldEdit.getInstance().getPlatformManager().register(platform); + + config = new ForgeConfiguration(this); + + // TODO if (ModList.get().isLoaded("sponge")) { + // this.provider = new ForgePermissionsProvider.SpongePermissionsProvider(); + // } else { + this.provider = new ForgePermissionsProvider.VanillaPermissionsProvider(platform); + // } + } + + // TODO clean this up once Forge adds a proper API for this + private void setupRegistries(MinecraftServer server) { + // Blocks + for (ResourceLocation name : BuiltInRegistries.BLOCK.keySet()) { + if (BlockType.REGISTRY.get(name.toString()) == null) { + BlockType.REGISTRY.register(name.toString(), new BlockType(name.toString(), + input -> ForgeAdapter.adapt(ForgeAdapter.adapt(input.getBlockType()).defaultBlockState()))); + } + } + // Items + for (ResourceLocation name : BuiltInRegistries.ITEM.keySet()) { + if (ItemType.REGISTRY.get(name.toString()) == null) { + ItemType.REGISTRY.register(name.toString(), new ItemType(name.toString())); + } + } + // Entities + for (ResourceLocation name : BuiltInRegistries.ENTITY_TYPE.keySet()) { + if (EntityType.REGISTRY.get(name.toString()) == null) { + EntityType.REGISTRY.register(name.toString(), new EntityType(name.toString())); + } + } + // Biomes + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.BIOME).keySet()) { + if (BiomeType.REGISTRY.get(name.toString()) == null) { + BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); + } + } + // Tags + server.registryAccess().registryOrThrow(Registries.BLOCK).getTagNames().map(TagKey::location).forEach(name -> { + if (BlockCategory.REGISTRY.get(name.toString()) == null) { + BlockCategory.REGISTRY.register(name.toString(), new BlockCategory(name.toString())); + } + }); + server.registryAccess().registryOrThrow(Registries.ITEM).getTagNames().map(TagKey::location).forEach(name -> { + if (ItemCategory.REGISTRY.get(name.toString()) == null) { + ItemCategory.REGISTRY.register(name.toString(), new ItemCategory(name.toString())); + } + }); + } + + @SubscribeEvent + public void registerCommands(RegisterCommandsEvent event) { + WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent()); + + PlatformManager manager = WorldEdit.getInstance().getPlatformManager(); + Platform commandsPlatform = manager.queryCapability(Capability.USER_COMMANDS); + if (commandsPlatform != platform || !platform.isHookingEvents()) { + // We're not in control of commands/events -- do not register. + return; + } + + List commands = manager.getPlatformCommandManager().getCommandManager() + .getAllCommands().toList(); + for (Command command : commands) { + CommandWrapper.register(event.getDispatcher(), command); + Set perms = command.getCondition().as(PermissionCondition.class) + .map(PermissionCondition::getPermissions) + .orElseGet(Collections::emptySet); + if (!perms.isEmpty()) { + perms.forEach(getPermissionsProvider()::registerPermission); + } + } + } + + @SubscribeEvent + public void serverAboutToStart(ServerAboutToStartEvent event) { + final Path delChunks = workingDir.resolve(DELCHUNKS_FILE_NAME); + if (Files.exists(delChunks)) { + ChunkDeleter.runFromFile(delChunks, true); + } + } + + @SubscribeEvent + public void serverStopping(ServerStoppingEvent event) { + WorldEdit worldEdit = WorldEdit.getInstance(); + worldEdit.getSessionManager().unload(); + WorldEdit.getInstance().getEventBus().post(new PlatformUnreadyEvent(platform)); + } + + @SubscribeEvent + public void serverStarted(ServerStartedEvent event) { + setupRegistries(event.getServer()); + + config.load(); + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform)); + } + + private boolean skipEvents() { + return platform == null || !platform.isHookingEvents(); + } + + private boolean skipInteractionEvent(Player player, InteractionHand hand) { + return skipEvents() || hand != InteractionHand.MAIN_HAND || player.level().isClientSide || !(player instanceof ServerPlayer); + } + + @SubscribeEvent + public void onLeftClickBlock(PlayerInteractEvent.LeftClickBlock event) { + if (skipInteractionEvent(event.getEntity(), event.getHand()) || event.getUseItem() == Event.Result.DENY) { + return; + } + + ServerPlayer playerEntity = (ServerPlayer) event.getEntity(); + WorldEdit we = WorldEdit.getInstance(); + ForgePlayer player = adaptPlayer(playerEntity); + ForgeWorld world = getWorld((ServerLevel) playerEntity.level()); + Direction direction = ForgeAdapter.adaptEnumFacing(event.getFace()); + + BlockPos blockPos = event.getPos(); + Location pos = new Location(world, blockPos.getX(), blockPos.getY(), blockPos.getZ()); + + boolean result = we.handleBlockLeftClick(player, pos, direction) || we.handleArmSwing(player); + debouncer.setLastInteraction(player, result); + + if (result) { + event.setCanceled(true); + } + } + + @SubscribeEvent + public void onRightClickBlock(PlayerInteractEvent.RightClickBlock event) { + if (skipInteractionEvent(event.getEntity(), event.getHand()) || event.getUseItem() == Event.Result.DENY) { + return; + } + + ServerPlayer playerEntity = (ServerPlayer) event.getEntity(); + WorldEdit we = WorldEdit.getInstance(); + ForgePlayer player = adaptPlayer(playerEntity); + ForgeWorld world = getWorld((ServerLevel) playerEntity.level()); + Direction direction = ForgeAdapter.adaptEnumFacing(event.getFace()); + + BlockPos blockPos = event.getPos(); + Location pos = new Location(world, blockPos.getX(), blockPos.getY(), blockPos.getZ()); + + boolean result = we.handleBlockRightClick(player, pos, direction) || we.handleRightClick(player); + debouncer.setLastInteraction(player, result); + + if (result) { + event.setCanceled(true); + } + } + + public void onLeftClickAir(ServerPlayer playerEntity, InteractionHand hand) { + if (skipInteractionEvent(playerEntity, hand)) { + return; + } + + WorldEdit we = WorldEdit.getInstance(); + ForgePlayer player = adaptPlayer(playerEntity); + + Optional previousResult = debouncer.getDuplicateInteractionResult(player); + if (previousResult.isPresent()) { + return; + } + + boolean result = we.handleArmSwing(player); + debouncer.setLastInteraction(player, result); + } + + @SubscribeEvent + public void onRightClickItem(PlayerInteractEvent.RightClickItem event) { + if (skipInteractionEvent(event.getEntity(), event.getHand())) { + return; + } + + ServerPlayer playerEntity = (ServerPlayer) event.getEntity(); + WorldEdit we = WorldEdit.getInstance(); + ForgePlayer player = adaptPlayer(playerEntity); + + Optional previousResult = debouncer.getDuplicateInteractionResult(player); + if (previousResult.isPresent()) { + if (previousResult.get()) { + event.setCanceled(true); + } + return; + } + + boolean result = we.handleRightClick(player); + debouncer.setLastInteraction(player, result); + + if (result) { + event.setCanceled(true); + } + } + + @SubscribeEvent + public void onCommandEvent(CommandEvent event) throws CommandSyntaxException { + ParseResults parseResults = event.getParseResults(); + if (parseResults.getContext().getSource().getEntity() instanceof ServerPlayer player && player.level().isClientSide) { + return; + } + if (parseResults.getContext().getCommand() != CommandWrapper.FAKE_COMMAND) { + return; + } + event.setCanceled(true); + WorldEdit.getInstance().getEventBus().post(new com.sk89q.worldedit.event.platform.CommandEvent( + adaptCommandSource(parseResults.getContext().getSource()), + "/" + parseResults.getReader().getString() + )); + } + + @SubscribeEvent + public void onPlayerLogOut(PlayerEvent.PlayerLoggedOutEvent event) { + if (event.getEntity() instanceof ServerPlayer player) { + debouncer.clearInteraction(adaptPlayer(player)); + + WorldEdit.getInstance().getEventBus() + .post(new SessionIdleEvent(new ForgePlayer.SessionKeyImpl(player))); + } + } + + /** + * Get the configuration. + * + * @return the Forge configuration + */ + ForgeConfiguration getConfig() { + return this.config; + } + + /** + * Get the session for a player. + * + * @param player the player + * @return the session + */ + public LocalSession getSession(ServerPlayer player) { + checkNotNull(player); + return WorldEdit.getInstance().getSessionManager().get(adaptPlayer(player)); + } + + /** + * Get the WorldEdit proxy for the given world. + * + * @param world the world + * @return the WorldEdit world + */ + public ForgeWorld getWorld(ServerLevel world) { + checkNotNull(world); + return new ForgeWorld(world); + } + + /** + * Get the WorldEdit proxy for the platform. + * + * @return the WorldEdit platform + */ + public Platform getPlatform() { + return this.platform; + } + + /** + * Get the working directory where WorldEdit's files are stored. + * + * @return the working directory + */ + public Path getWorkingDir() { + return this.workingDir; + } + + /** + * Get the version of the WorldEdit-for-Forge implementation. + * + * @return a version string + */ + String getInternalVersion() { + return container.getModInfo().getVersion().toString(); + } + + public void setPermissionsProvider(ForgePermissionsProvider provider) { + this.provider = provider; + } + + public ForgePermissionsProvider getPermissionsProvider() { + return provider; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java b/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java new file mode 100644 index 0000000..36d5ea3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java @@ -0,0 +1,80 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.neoforge.server.ServerLifecycleHooks; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * Caches data that cannot be accessed from another thread safely. + */ +public class ThreadSafeCache { + + private static final long REFRESH_DELAY = 1000 * 30; + private static final ThreadSafeCache INSTANCE = new ThreadSafeCache(); + private Set onlineIds = Collections.emptySet(); + private long lastRefresh = 0; + + /** + * Get an concurrent-safe set of UUIDs of online players. + * + * @return a set of UUIDs + */ + public Set getOnlineIds() { + return onlineIds; + } + + @SubscribeEvent + public void tickStart(TickEvent event) { + long now = System.currentTimeMillis(); + + if (now - lastRefresh > REFRESH_DELAY) { + Set onlineIds = new HashSet<>(); + + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server == null) { + return; + } + for (ServerPlayer player : server.getPlayerList().getPlayers()) { + if (player != null) { + onlineIds.add(player.getUUID()); + } + } + + this.onlineIds = new CopyOnWriteArraySet<>(onlineIds); + + lastRefresh = now; + } + } + + public static ThreadSafeCache getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java b/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java new file mode 100644 index 0000000..277ffd2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java @@ -0,0 +1,65 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import com.mojang.authlib.GameProfile; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.stats.Stat; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; + +import java.util.UUID; + +public class WorldEditFakePlayer extends ServerPlayer { + private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); + private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation( + "en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false + ); + + public WorldEditFakePlayer(ServerLevel world) { + super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO); + } + + @Override + public void tick() { + } + + @Override + public void awardStat(Stat stat, int incrementer) { + } + + @Override + public void awardStat(Stat stat) { + } + + @Override + public void displayClientMessage(Component message, boolean actionBar) { + super.displayClientMessage(message, actionBar); + } + + @Override + public boolean isInvulnerableTo(DamageSource damageSource) { + return true; + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/WorldEditGenListener.java b/src/main/java/com/sk89q/worldedit/forge/WorldEditGenListener.java new file mode 100644 index 0000000..2904fea --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/WorldEditGenListener.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge; + +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkStatus; + +import javax.annotation.Nullable; + +// For now, this does nothing, but might be useful later for regen progress communication. +class WorldEditGenListener implements ChunkProgressListener { + @Override + public void updateSpawnPos(ChunkPos chunkPos) { + } + + @Override + public void onStatusChange(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) { + } + + @Override + public void start() { + } + + @Override + public void stop() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/internal/ExtendedChunk.java b/src/main/java/com/sk89q/worldedit/forge/internal/ExtendedChunk.java new file mode 100644 index 0000000..7fb9702 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/internal/ExtendedChunk.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.internal; + +import com.sk89q.worldedit.util.SideEffect; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; + +import javax.annotation.Nullable; + +public interface ExtendedChunk { + /** + * {@link ChunkAccess#setBlockState(BlockPos, BlockState, boolean)} with the extra + * {@link SideEffect#UPDATE} flag. + * + * @param pos the position to set + * @param state the state to set + * @param moved I honestly have no idea and can't be bothered to investigate, we pass {@code + * false} + * @param update the update flag, see side-effect for details + * @return the old block state, or {@code null} if unchanged + */ + @Nullable + BlockState setBlockState(BlockPos pos, BlockState state, boolean moved, boolean update); +} diff --git a/src/main/java/com/sk89q/worldedit/forge/internal/ForgeTransmogrifier.java b/src/main/java/com/sk89q/worldedit/forge/internal/ForgeTransmogrifier.java new file mode 100644 index 0000000..3822471 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/internal/ForgeTransmogrifier.java @@ -0,0 +1,128 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.internal; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.forge.ForgeAdapter; +import com.sk89q.worldedit.registry.state.BooleanProperty; +import com.sk89q.worldedit.registry.state.DirectionalProperty; +import com.sk89q.worldedit.registry.state.EnumProperty; +import com.sk89q.worldedit.registry.state.IntegerProperty; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.DirectionProperty; + +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; + +/** + * Raw, un-cached transformations. + */ +public class ForgeTransmogrifier { + + private static final LoadingCache, Property> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property property) throws Exception { + if (property instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(property.getName(), ImmutableList.copyOf(((net.minecraft.world.level.block.state.properties.BooleanProperty) property).getPossibleValues())); + } + if (property instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(property.getName(), ImmutableList.copyOf(((net.minecraft.world.level.block.state.properties.IntegerProperty) property).getPossibleValues())); + } + if (property instanceof DirectionProperty) { + return new DirectionalProperty(property.getName(), ((DirectionProperty) property).getPossibleValues().stream() + .map(ForgeAdapter::adaptEnumFacing) + .collect(Collectors.toList())); + } + if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + // Note: do not make x.getSerializedName a method reference. + // It will cause runtime bootstrap exceptions. + //noinspection Convert2MethodRef + return new EnumProperty(property.getName(), ((net.minecraft.world.level.block.state.properties.EnumProperty) property).getPossibleValues().stream() + .map(x -> x.getSerializedName()) + .collect(Collectors.toList())); + } + return new IPropertyAdapter<>(property); + } + }); + + public static Property transmogToWorldEditProperty(net.minecraft.world.level.block.state.properties.Property property) { + return PROPERTY_CACHE.getUnchecked(property); + } + + public static Map, Object> transmogToWorldEditProperties(BlockType block, Map, Comparable> mcProps) { + Map, Object> props = new TreeMap<>(Comparator.comparing(Property::getName)); + for (Map.Entry, Comparable> prop : mcProps.entrySet()) { + Object value = prop.getValue(); + if (prop.getKey() instanceof DirectionProperty) { + value = ForgeAdapter.adaptEnumFacing((net.minecraft.core.Direction) value); + } else if (prop.getKey() instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + value = ((StringRepresentable) value).getSerializedName(); + } + props.put(block.getProperty(prop.getKey().getName()), value); + } + return props; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static net.minecraft.world.level.block.state.BlockState transmogToMinecraftProperties(StateDefinition stateContainer, net.minecraft.world.level.block.state.BlockState newState, Map, Object> states) { + for (Map.Entry, Object> state : states.entrySet()) { + net.minecraft.world.level.block.state.properties.Property property = stateContainer.getProperty(state.getKey().getName()); + Comparable value = (Comparable) state.getValue(); + // we may need to adapt this value, depending on the source prop + if (property instanceof DirectionProperty) { + Direction dir = (Direction) value; + value = ForgeAdapter.adapt(dir); + } else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + String enumName = (String) value; + value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property).getValue((String) value) + .orElseThrow(() -> new IllegalStateException("Enum property " + property.getName() + " does not contain " + enumName)); + } + + newState = newState.setValue(property, value); + } + return newState; + } + + public static net.minecraft.world.level.block.state.BlockState transmogToMinecraft(BlockState blockState) { + Block mcBlock = ForgeAdapter.adapt(blockState.getBlockType()); + net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); + Map, Object> states = blockState.getStates(); + return transmogToMinecraftProperties(mcBlock.getStateDefinition(), newState, states); + } + + public static BlockState transmogToWorldEdit(net.minecraft.world.level.block.state.BlockState blockState) { + BlockType blockType = ForgeAdapter.adapt(blockState.getBlock()); + return blockType.getState(transmogToWorldEditProperties(blockType, blockState.getValues())); + } + + private ForgeTransmogrifier() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/internal/ForgeWorldNativeAccess.java b/src/main/java/com/sk89q/worldedit/forge/internal/ForgeWorldNativeAccess.java new file mode 100644 index 0000000..90bc692 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/internal/ForgeWorldNativeAccess.java @@ -0,0 +1,167 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.internal; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.forge.ForgeAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; + +import java.lang.ref.WeakReference; +import java.util.Objects; +import javax.annotation.Nullable; + +public class ForgeWorldNativeAccess implements WorldNativeAccess { + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + + private final WeakReference world; + private SideEffectSet sideEffectSet; + + public ForgeWorldNativeAccess(WeakReference world) { + this.world = world; + } + + private ServerLevel getWorld() { + return Objects.requireNonNull(world.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getWorld().getChunk(x, z); + } + + @Override + public BlockState toNative(com.sk89q.worldedit.world.block.BlockState state) { + int stateId = BlockStateIdAccess.getBlockStateId(state); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ForgeAdapter.adapt(state); + } + + @Override + public BlockState getBlockState(LevelChunk chunk, BlockPos position) { + return chunk.getBlockState(position); + } + + @Nullable + @Override + public BlockState setBlockState(LevelChunk chunk, BlockPos position, BlockState state) { + if (chunk instanceof ExtendedChunk) { + return ((ExtendedChunk) chunk).setBlockState( + position, state, false, sideEffectSet.shouldApply(SideEffect.UPDATE) + ); + } + return chunk.setBlockState(position, state, false); + } + + @Override + public BlockState getValidBlockForPosition(BlockState block, BlockPos position) { + return Block.updateFromNeighbourShapes(block, getWorld(), position); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos position) { + getWorld().getChunkSource().getLightEngine().checkBlock(position); + } + + @Override + public boolean updateTileEntity(BlockPos position, CompoundTag tag) { + net.minecraft.nbt.CompoundTag nativeTag = NBTConverter.toNative(tag); + return TileEntityUtils.setTileEntity(getWorld(), position, nativeTag); + } + + @Override + public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, BlockState oldState, BlockState newState) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk chunk) { + return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); + } + + @Override + public void markBlockChanged(LevelChunk chunk, BlockPos position) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().getChunkSource().blockChanged(position); + } + } + + @Override + public void notifyNeighbors(BlockPos pos, BlockState oldState, BlockState newState) { + ServerLevel world = getWorld(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + world.updateNeighborsAt(pos, oldState.getBlock()); + } else { + // Manually update each side + Block block = oldState.getBlock(); + world.neighborChanged(pos.west(), block, pos); + world.neighborChanged(pos.east(), block, pos); + world.neighborChanged(pos.below(), block, pos); + world.neighborChanged(pos.above(), block, pos); + world.neighborChanged(pos.north(), block, pos); + world.neighborChanged(pos.south(), block, pos); + } + if (newState.hasAnalogOutputSignal()) { + world.updateNeighbourForOutputSignal(pos, newState.getBlock()); + } + } + + @Override + public void updateBlock(BlockPos pos, BlockState oldState, BlockState newState) { + ServerLevel world = getWorld(); + newState.onPlace(world, pos, oldState, false); + } + + @Override + public void updateNeighbors(BlockPos pos, BlockState oldState, BlockState newState, int recursionLimit) { + ServerLevel world = getWorld(); + oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + } + + @Override + public void onBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) { + getWorld().onBlockStateChange(pos, oldState, newState); + newState.onBlockStateChange(getWorld(), pos, oldState); + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/internal/IPropertyAdapter.java b/src/main/java/com/sk89q/worldedit/forge/internal/IPropertyAdapter.java new file mode 100644 index 0000000..e17f673 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/internal/IPropertyAdapter.java @@ -0,0 +1,70 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.internal; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.registry.state.Property; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; + +class IPropertyAdapter> implements Property { + + private final net.minecraft.world.level.block.state.properties.Property property; + private final List values; + + public IPropertyAdapter(net.minecraft.world.level.block.state.properties.Property property) { + this.property = property; + this.values = ImmutableList.copyOf(property.getPossibleValues()); + } + + @Override + public String getName() { + return property.getName(); + } + + @Override + public List getValues() { + return values; + } + + @Override + public T getValueFor(String string) throws IllegalArgumentException { + Optional val = property.getValue(string); + checkArgument(val.isPresent(), "%s has no value for %s", getName(), string); + return val.get(); + } + + @Override + public int hashCode() { + return getName().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Property)) { + return false; + } + return getName().equals(((Property) obj).getName()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java b/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java new file mode 100644 index 0000000..4ca1133 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java @@ -0,0 +1,265 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.internal; + +import com.sk89q.jnbt.ByteArrayTag; +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.DoubleTag; +import com.sk89q.jnbt.EndTag; +import com.sk89q.jnbt.FloatTag; +import com.sk89q.jnbt.IntArrayTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.LongArrayTag; +import com.sk89q.jnbt.LongTag; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * Converts between JNBT and Minecraft NBT classes. + */ +public final class NBTConverter { + + private NBTConverter() { + } + + public static net.minecraft.nbt.Tag toNative(Tag tag) { + if (tag instanceof IntArrayTag) { + return toNative((IntArrayTag) tag); + + } else if (tag instanceof ListTag) { + return toNative((ListTag) tag); + + } else if (tag instanceof LongTag) { + return toNative((LongTag) tag); + + } else if (tag instanceof LongArrayTag) { + return toNative((LongArrayTag) tag); + + } else if (tag instanceof StringTag) { + return toNative((StringTag) tag); + + } else if (tag instanceof IntTag) { + return toNative((IntTag) tag); + + } else if (tag instanceof ByteTag) { + return toNative((ByteTag) tag); + + } else if (tag instanceof ByteArrayTag) { + return toNative((ByteArrayTag) tag); + + } else if (tag instanceof CompoundTag) { + return toNative((CompoundTag) tag); + + } else if (tag instanceof FloatTag) { + return toNative((FloatTag) tag); + + } else if (tag instanceof ShortTag) { + return toNative((ShortTag) tag); + + } else if (tag instanceof DoubleTag) { + return toNative((DoubleTag) tag); + } else { + throw new IllegalArgumentException("Can't convert tag of type " + tag.getClass().getCanonicalName()); + } + } + + public static net.minecraft.nbt.IntArrayTag toNative(IntArrayTag tag) { + int[] value = tag.getValue(); + return new net.minecraft.nbt.IntArrayTag(Arrays.copyOf(value, value.length)); + } + + public static net.minecraft.nbt.ListTag toNative(ListTag tag) { + net.minecraft.nbt.ListTag list = new net.minecraft.nbt.ListTag(); + for (Tag child : tag.getValue()) { + if (child instanceof EndTag) { + continue; + } + list.add(toNative(child)); + } + return list; + } + + public static net.minecraft.nbt.LongTag toNative(LongTag tag) { + return net.minecraft.nbt.LongTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.LongArrayTag toNative(LongArrayTag tag) { + return new net.minecraft.nbt.LongArrayTag(tag.getValue().clone()); + } + + public static net.minecraft.nbt.StringTag toNative(StringTag tag) { + return net.minecraft.nbt.StringTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.IntTag toNative(IntTag tag) { + return net.minecraft.nbt.IntTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.ByteTag toNative(ByteTag tag) { + return net.minecraft.nbt.ByteTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.ByteArrayTag toNative(ByteArrayTag tag) { + return new net.minecraft.nbt.ByteArrayTag(tag.getValue().clone()); + } + + public static net.minecraft.nbt.CompoundTag toNative(CompoundTag tag) { + net.minecraft.nbt.CompoundTag compound = new net.minecraft.nbt.CompoundTag(); + for (Entry child : tag.getValue().entrySet()) { + compound.put(child.getKey(), toNative(child.getValue())); + } + return compound; + } + + public static net.minecraft.nbt.FloatTag toNative(FloatTag tag) { + return net.minecraft.nbt.FloatTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.ShortTag toNative(ShortTag tag) { + return net.minecraft.nbt.ShortTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.DoubleTag toNative(DoubleTag tag) { + return net.minecraft.nbt.DoubleTag.valueOf(tag.getValue()); + } + + public static Tag fromNative(net.minecraft.nbt.Tag other) { + if (other instanceof net.minecraft.nbt.IntArrayTag) { + return fromNative((net.minecraft.nbt.IntArrayTag) other); + + } else if (other instanceof net.minecraft.nbt.ListTag) { + return fromNative((net.minecraft.nbt.ListTag) other); + + } else if (other instanceof net.minecraft.nbt.EndTag) { + return fromNative((net.minecraft.nbt.EndTag) other); + + } else if (other instanceof net.minecraft.nbt.LongTag) { + return fromNative((net.minecraft.nbt.LongTag) other); + + } else if (other instanceof net.minecraft.nbt.LongArrayTag) { + return fromNative((net.minecraft.nbt.LongArrayTag) other); + + } else if (other instanceof net.minecraft.nbt.StringTag) { + return fromNative((net.minecraft.nbt.StringTag) other); + + } else if (other instanceof net.minecraft.nbt.IntTag) { + return fromNative((net.minecraft.nbt.IntTag) other); + + } else if (other instanceof net.minecraft.nbt.ByteTag) { + return fromNative((net.minecraft.nbt.ByteTag) other); + + } else if (other instanceof net.minecraft.nbt.ByteArrayTag) { + return fromNative((net.minecraft.nbt.ByteArrayTag) other); + + } else if (other instanceof net.minecraft.nbt.CompoundTag) { + return fromNative((net.minecraft.nbt.CompoundTag) other); + + } else if (other instanceof net.minecraft.nbt.FloatTag) { + return fromNative((net.minecraft.nbt.FloatTag) other); + + } else if (other instanceof net.minecraft.nbt.ShortTag) { + return fromNative((net.minecraft.nbt.ShortTag) other); + + } else if (other instanceof net.minecraft.nbt.DoubleTag) { + return fromNative((net.minecraft.nbt.DoubleTag) other); + } else { + throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName()); + } + } + + public static IntArrayTag fromNative(net.minecraft.nbt.IntArrayTag other) { + int[] value = other.getAsIntArray(); + return new IntArrayTag(Arrays.copyOf(value, value.length)); + } + + public static ListTag fromNative(net.minecraft.nbt.ListTag other) { + other = other.copy(); + List list = new ArrayList<>(); + Class listClass = StringTag.class; + int tags = other.size(); + for (int i = 0; i < tags; i++) { + Tag child = fromNative(other.remove(0)); + list.add(child); + listClass = child.getClass(); + } + return new ListTag(listClass, list); + } + + public static EndTag fromNative(net.minecraft.nbt.EndTag other) { + return new EndTag(); + } + + public static LongTag fromNative(net.minecraft.nbt.LongTag other) { + return new LongTag(other.getAsLong()); + } + + public static LongArrayTag fromNative(net.minecraft.nbt.LongArrayTag other) { + return new LongArrayTag(other.getAsLongArray().clone()); + } + + public static StringTag fromNative(net.minecraft.nbt.StringTag other) { + return new StringTag(other.getAsString()); + } + + public static IntTag fromNative(net.minecraft.nbt.IntTag other) { + return new IntTag(other.getAsInt()); + } + + public static ByteTag fromNative(net.minecraft.nbt.ByteTag other) { + return new ByteTag(other.getAsByte()); + } + + public static ByteArrayTag fromNative(net.minecraft.nbt.ByteArrayTag other) { + return new ByteArrayTag(other.getAsByteArray().clone()); + } + + public static CompoundTag fromNative(net.minecraft.nbt.CompoundTag other) { + Set tags = other.getAllKeys(); + Map map = new HashMap<>(); + for (String tagName : tags) { + map.put(tagName, fromNative(other.get(tagName))); + } + return new CompoundTag(map); + } + + public static FloatTag fromNative(net.minecraft.nbt.FloatTag other) { + return new FloatTag(other.getAsFloat()); + } + + public static ShortTag fromNative(net.minecraft.nbt.ShortTag other) { + return new ShortTag(other.getAsShort()); + } + + public static DoubleTag fromNative(net.minecraft.nbt.DoubleTag other) { + return new DoubleTag(other.getAsDouble()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/forge/internal/TileEntityUtils.java b/src/main/java/com/sk89q/worldedit/forge/internal/TileEntityUtils.java new file mode 100644 index 0000000..d49574f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/internal/TileEntityUtils.java @@ -0,0 +1,55 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.internal; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; + +/** + * Utility methods for setting tile entities in the world. + */ +public final class TileEntityUtils { + + private TileEntityUtils() { + } + + /** + * Set a tile entity at the given location using the tile entity ID from + * the tag. + * + * @param world the world + * @param position the position + * @param tag the tag for the tile entity + */ + static boolean setTileEntity(Level world, BlockPos position, CompoundTag tag) { + BlockEntity tileEntity = BlockEntity.loadStatic(position, world.getBlockState(position), tag); + if (tileEntity == null) { + return false; + } + world.setBlockEntity(tileEntity); + return true; + } + + public static CompoundTag copyNbtData(BlockEntity tile) { + return tile.saveWithId(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/mixin/AccessorServerPlayerGameMode.java b/src/main/java/com/sk89q/worldedit/forge/mixin/AccessorServerPlayerGameMode.java new file mode 100644 index 0000000..5bb01ab --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/mixin/AccessorServerPlayerGameMode.java @@ -0,0 +1,31 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.mixin; + +import net.minecraft.server.level.ServerPlayerGameMode; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ServerPlayerGameMode.class) +public interface AccessorServerPlayerGameMode { + + @Accessor("isDestroyingBlock") + boolean isDestroyingBlock(); +} diff --git a/src/main/java/com/sk89q/worldedit/forge/mixin/MixinLevelChunkSetBlockHook.java b/src/main/java/com/sk89q/worldedit/forge/mixin/MixinLevelChunkSetBlockHook.java new file mode 100644 index 0000000..4bfa690 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/mixin/MixinLevelChunkSetBlockHook.java @@ -0,0 +1,85 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.mixin; + +import com.sk89q.worldedit.forge.internal.ExtendedChunk; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.levelgen.blending.BlendingData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; + +import javax.annotation.Nullable; + +@Mixin(LevelChunk.class) +public abstract class MixinLevelChunkSetBlockHook extends ChunkAccess implements ExtendedChunk { + private boolean shouldUpdate = true; + + public MixinLevelChunkSetBlockHook(ChunkPos chunkPos, UpgradeData upgradeData, LevelHeightAccessor levelHeightAccessor, Registry registry, long l, @org.jetbrains.annotations.Nullable LevelChunkSection[] levelChunkSections, @org.jetbrains.annotations.Nullable BlendingData blendingData) { + super(chunkPos, upgradeData, levelHeightAccessor, registry, l, levelChunkSections, blendingData); + } + + @Nullable + @Override + public BlockState setBlockState(BlockPos pos, BlockState state, boolean moved, boolean update) { + // save the state for the hook + shouldUpdate = update; + try { + return setBlockState(pos, state, moved); + } finally { + // restore natural mode + shouldUpdate = true; + } + } + + @Redirect( + method = "setBlockState", + slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z") + ), + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;onPlace(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Z)V") + ) + public void setBlockStateHook(BlockState target, Level world, BlockPos pos, BlockState old, boolean move) { + boolean localShouldUpdate; + MinecraftServer server = world.getServer(); + if (server == null || Thread.currentThread() != server.getRunningThread()) { + // We're not on the server thread for some reason, WorldEdit will never be here + // so we'll just ignore our flag + localShouldUpdate = true; + } else { + localShouldUpdate = shouldUpdate; + } + if (localShouldUpdate) { + target.onPlace(world, pos, old, move); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/mixin/MixinServerGamePacketListenerImpl.java b/src/main/java/com/sk89q/worldedit/forge/mixin/MixinServerGamePacketListenerImpl.java new file mode 100644 index 0000000..de559a8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/mixin/MixinServerGamePacketListenerImpl.java @@ -0,0 +1,59 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.mixin; + +import com.sk89q.worldedit.forge.ForgeWorldEdit; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.network.protocol.game.ServerboundSwingPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerGamePacketListenerImpl.class) +public class MixinServerGamePacketListenerImpl { + @Shadow + public ServerPlayer player; + + private int ignoreSwingPackets; + + @Inject(method = "handleAnimate", at = @At("HEAD")) + private void onAnimate(ServerboundSwingPacket packet, CallbackInfo ci) { + if (!((AccessorServerPlayerGameMode) this.player.gameMode).isDestroyingBlock()) { + if (this.ignoreSwingPackets > 0) { + this.ignoreSwingPackets--; + } else if (ForgeWorldEdit.inst != null) { + ForgeWorldEdit.inst.onLeftClickAir(this.player, packet.getHand()); + } + } + } + + @Inject(method = "handlePlayerAction", at = @At("HEAD")) + private void onAction(ServerboundPlayerActionPacket packet, CallbackInfo ci) { + switch (packet.getAction()) { + case DROP_ITEM, DROP_ALL_ITEMS, START_DESTROY_BLOCK -> this.ignoreSwingPackets++; + default -> { + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java b/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java new file mode 100644 index 0000000..9bacaef --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.net.handler; + +import com.sk89q.worldedit.forge.ForgeWorldEdit; +import net.minecraft.resources.ResourceLocation; + +final class PacketHandlerUtil { + private PacketHandlerUtil() { + } + + static ChannelBuilder buildLenientHandler(String id, int protocolVersion) { + final Channel.VersionTest validator = validateLenient(protocolVersion); + return ChannelBuilder + .named(new ResourceLocation(ForgeWorldEdit.MOD_ID, id)) + .clientAcceptedVersions(validator) + .serverAcceptedVersions(validator) + .networkProtocolVersion(protocolVersion); + } + + private static Channel.VersionTest validateLenient(int protocolVersion) { + return (status, remoteVersion) -> + protocolVersion == remoteVersion + // These two ignore protocolVersion anyway so it doesn't matter what it is + || Channel.VersionTest.ACCEPT_MISSING.accepts(status, protocolVersion) + || Channel.VersionTest.ACCEPT_VANILLA.accepts(status, protocolVersion); + } +} diff --git a/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java b/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java new file mode 100644 index 0000000..c15c6e9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java @@ -0,0 +1,60 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.forge.net.handler; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.forge.ForgePlayer; +import com.sk89q.worldedit.forge.ForgeWorldEdit; +import net.minecraft.network.Connection; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.neoforge.network.NetworkEvent; +import net.neoforged.neoforge.network.event.EventNetworkChannel; + +import java.nio.charset.StandardCharsets; + +import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; + +public final class WECUIPacketHandler { + private WECUIPacketHandler() { + } + + private static final int PROTOCOL_VERSION = 1; + private static final EventNetworkChannel HANDLER = PacketHandlerUtil + .buildLenientHandler(ForgeWorldEdit.CUI_PLUGIN_CHANNEL, PROTOCOL_VERSION) + .eventNetworkChannel(); + + public static void init() { + HANDLER.addListener(WECUIPacketHandler::onPacketData); + } + + public static void onPacketData(NetworkEvent.ServerCustomPayloadEvent event) { + ServerPlayer player = event.getSource().getSender(); + LocalSession session = ForgeWorldEdit.inst.getSession(player); + String text = event.getPayload().toString(StandardCharsets.UTF_8); + final ForgePlayer actor = adaptPlayer(player); + session.handleCUIInitializationMessage(text, actor); + } + + public static void send(Connection connection, FriendlyByteBuf friendlyByteBuf) { + HANDLER.send(friendlyByteBuf, connection); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/CombinedRegionFunction.java b/src/main/java/com/sk89q/worldedit/function/CombinedRegionFunction.java new file mode 100644 index 0000000..352cf74 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/CombinedRegionFunction.java @@ -0,0 +1,94 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.math.BlockVector3; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Executes several region functions in order. + */ +public class CombinedRegionFunction implements RegionFunction { + + private final List functions = new ArrayList<>(); + + /** + * Create a combined region function. + */ + public CombinedRegionFunction() { + } + + /** + * Create a combined region function. + * + * @param functions a list of functions to match + */ + public CombinedRegionFunction(Collection functions) { + checkNotNull(functions); + this.functions.addAll(functions); + } + + /** + * Create a combined region function. + * + * @param function an array of functions to match + */ + public CombinedRegionFunction(RegionFunction... function) { + this(Arrays.asList(checkNotNull(function))); + } + + /** + * Add the given functions to the list of functions to call. + * + * @param functions a list of functions + */ + public void add(Collection functions) { + checkNotNull(functions); + this.functions.addAll(functions); + } + + /** + * Add the given functions to the list of functions to call. + * + * @param function an array of functions + */ + public void add(RegionFunction... function) { + add(Arrays.asList(checkNotNull(function))); + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + boolean ret = false; + for (RegionFunction function : functions) { + if (function.apply(position)) { + ret = true; + } + } + return ret; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/Contextual.java b/src/main/java/com/sk89q/worldedit/function/Contextual.java new file mode 100644 index 0000000..363011d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/Contextual.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +public interface Contextual { + + T createFromContext(EditContext context); + +} diff --git a/src/main/java/com/sk89q/worldedit/function/EditContext.java b/src/main/java/com/sk89q/worldedit/function/EditContext.java new file mode 100644 index 0000000..fafa59d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/EditContext.java @@ -0,0 +1,73 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class EditContext { + + private Extent destination; + @Nullable private Region region; + @Nullable private Pattern fill; + @Nullable private LocalSession session; + + public Extent getDestination() { + return destination; + } + + public void setDestination(Extent destination) { + checkNotNull(destination, "destination"); + this.destination = destination; + } + + @Nullable + public Region getRegion() { + return region; + } + + public void setRegion(@Nullable Region region) { + this.region = region; + } + + @Nullable + public Pattern getFill() { + return fill; + } + + public void setFill(@Nullable Pattern fill) { + this.fill = fill; + } + + @Nullable + public LocalSession getSession() { + return session; + } + + public void setSession(@Nullable LocalSession session) { + this.session = session; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/EntityFunction.java b/src/main/java/com/sk89q/worldedit/function/EntityFunction.java new file mode 100644 index 0000000..f697872 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/EntityFunction.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Entity; + +/** + * Applies a function to entities. + */ +public interface EntityFunction { + + /** + * Apply the function to the entity. + * + * @param entity the entity + * @return true if something was changed + * @throws WorldEditException thrown on an error + */ + boolean apply(Entity entity) throws WorldEditException; + +} diff --git a/src/main/java/com/sk89q/worldedit/function/FlatRegionFunction.java b/src/main/java/com/sk89q/worldedit/function/FlatRegionFunction.java new file mode 100644 index 0000000..0529dc1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/FlatRegionFunction.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.regions.FlatRegion; + +/** + * Performs a function on the columns in a {@link FlatRegion}, or also + * known as vectors with only X and Z components (where Y is height). + */ +public interface FlatRegionFunction { + + /** + * Apply the function to the given position. + * + * @param position the position + * @return true if something was changed + * @throws WorldEditException thrown on an error + */ + boolean apply(BlockVector2 position) throws WorldEditException; + +} diff --git a/src/main/java/com/sk89q/worldedit/function/FlatRegionMaskingFilter.java b/src/main/java/com/sk89q/worldedit/function/FlatRegionMaskingFilter.java new file mode 100644 index 0000000..bc21c25 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/FlatRegionMaskingFilter.java @@ -0,0 +1,57 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.mask.Mask2D; +import com.sk89q.worldedit.math.BlockVector2; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Passes calls to {@link #apply(BlockVector2)} to the + * delegate {@link FlatRegionFunction} if they + * match the given mask. + */ +public class FlatRegionMaskingFilter implements FlatRegionFunction { + + private final FlatRegionFunction function; + private final Mask2D mask; + + /** + * Create a new masking filter. + * + * @param mask the mask + * @param function the delegate function to call + */ + public FlatRegionMaskingFilter(Mask2D mask, FlatRegionFunction function) { + checkNotNull(function); + checkNotNull(mask); + + this.mask = mask; + this.function = function; + } + + @Override + public boolean apply(BlockVector2 position) throws WorldEditException { + return mask.test(position) && function.apply(position); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/GroundFunction.java b/src/main/java/com/sk89q/worldedit/function/GroundFunction.java new file mode 100644 index 0000000..163c46d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/GroundFunction.java @@ -0,0 +1,94 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Applies a {@link RegionFunction} to the first ground block. + */ +public class GroundFunction implements LayerFunction { + + private Mask mask; + private final RegionFunction function; + private int affected; + + /** + * Create a new ground function. + * + * @param mask a mask + * @param function the function to apply + */ + public GroundFunction(Mask mask, RegionFunction function) { + checkNotNull(mask); + checkNotNull(function); + this.mask = mask; + this.function = function; + } + + /** + * Get the mask that determines what the ground consists of. + * + * @return a mask + */ + public Mask getMask() { + return mask; + } + + /** + * Set the mask that determines what the ground consists of. + * + * @param mask a mask + */ + public void setMask(Mask mask) { + checkNotNull(mask); + this.mask = mask; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public boolean isGround(BlockVector3 position) { + return mask.test(position); + } + + @Override + public boolean apply(BlockVector3 position, int depth) throws WorldEditException { + if (depth == 0) { + if (function.apply(position)) { + affected++; + return true; + } + } + return false; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java b/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java new file mode 100644 index 0000000..27c789b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.World; + +public final class ItemUseFunction implements RegionFunction { + private final World world; + private final BaseItem item; + private final Direction dir; + + public ItemUseFunction(World world, BaseItem item) { + this(world, item, Direction.UP); + } + + public ItemUseFunction(World world, BaseItem item, Direction dir) { + this.world = world; + this.item = item; + this.dir = dir; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + return world.useItem(position, item, dir); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/LayerFunction.java b/src/main/java/com/sk89q/worldedit/function/LayerFunction.java new file mode 100644 index 0000000..cfc6904 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/LayerFunction.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.visitor.LayerVisitor; +import com.sk89q.worldedit.math.BlockVector3; + +/** + * A function that takes a position and a depth. + */ +public interface LayerFunction { + + /** + * Returns whether the given block should be "passed through" when + * conducting the ground search. + * + * @param position return whether the given block is the ground + * @return true if the search should stop + */ + boolean isGround(BlockVector3 position); + + /** + * Apply the function to the given position. + * + *

The depth would be the number of blocks from the surface if + * a {@link LayerVisitor} was used.

+ * + * @param position the position + * @param depth the depth as a number starting from 0 + * @return true whether this method should be called for further layers + * @throws WorldEditException thrown on an error + */ + boolean apply(BlockVector3 position, int depth) throws WorldEditException; +} diff --git a/src/main/java/com/sk89q/worldedit/function/RegionFunction.java b/src/main/java/com/sk89q/worldedit/function/RegionFunction.java new file mode 100644 index 0000000..0e8c006 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/RegionFunction.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.math.BlockVector3; + +/** + * Performs a function on points in a region. + */ +public interface RegionFunction { + + /** + * Apply the function to the given position. + * + * @param position the position + * @return true if something was changed + * @throws WorldEditException thrown on an error + */ + boolean apply(BlockVector3 position) throws WorldEditException; + +} diff --git a/src/main/java/com/sk89q/worldedit/function/RegionMaskingFilter.java b/src/main/java/com/sk89q/worldedit/function/RegionMaskingFilter.java new file mode 100644 index 0000000..cde5edc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/RegionMaskingFilter.java @@ -0,0 +1,56 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Passes calls to {@link #apply(BlockVector3)} to the + * delegate {@link RegionFunction} if they + * match the given mask. + */ +public class RegionMaskingFilter implements RegionFunction { + + private final RegionFunction function; + private final Mask mask; + + /** + * Create a new masking filter. + * + * @param mask the mask + * @param function the function + */ + public RegionMaskingFilter(Mask mask, RegionFunction function) { + checkNotNull(function); + checkNotNull(mask); + this.mask = mask; + this.function = function; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + return mask.test(position) && function.apply(position); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java b/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java new file mode 100644 index 0000000..787091e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java @@ -0,0 +1,78 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.biome; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.FlatRegionFunction; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.pattern.BiomePattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Replaces the biome at the locations that this function is applied to. + */ +public class BiomeReplace implements FlatRegionFunction, RegionFunction { + + private final Extent extent; + private final BiomePattern biome; + + /** + * Create a new instance. + * + * @param extent an extent + * @param biome a biome + */ + public BiomeReplace(Extent extent, BiomeType biome) { + this(extent, (BiomePattern) biome); + } + + /** + * Create a new instance. + * + * @param extent the extent to apply this function to + * @param pattern the biome pattern to set + */ + public BiomeReplace(Extent extent, BiomePattern pattern) { + checkNotNull(extent); + checkNotNull(pattern); + this.extent = extent; + this.biome = pattern; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + return extent.setBiome(position, biome.applyBiome(position)); + } + + @Override + @Deprecated + public boolean apply(BlockVector2 position) throws WorldEditException { + boolean success = false; + for (int y = extent.getMinimumPoint().getY(); y <= extent.getMaximumPoint().getY(); y++) { + success |= apply(position.toBlockVector3(y)); + } + return success; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java b/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java new file mode 100644 index 0000000..07e375d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java @@ -0,0 +1,110 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.biome; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.FlatRegionFunction; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.world.biome.BiomeType; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Copies the biome from one extent to another. + */ +public class ExtentBiomeCopy implements FlatRegionFunction, RegionFunction { + + private final Extent source; + private final Extent destination; + private final BlockVector3 from; + private final BlockVector3 to; + private final Transform transform; + + /** + * Make a new biome copy. + * + * @param source the source extent + * @param from the source offset + * @param destination the destination extent + * @param to the destination offset + * @param transform a transform to apply to positions (after source offset, before destination offset) + * @deprecated use {@link ExtentBiomeCopy#ExtentBiomeCopy(Extent, BlockVector3, Extent, BlockVector3, Transform)} + */ + @Deprecated + public ExtentBiomeCopy(Extent source, BlockVector2 from, Extent destination, BlockVector2 to, Transform transform) { + checkNotNull(source); + checkNotNull(from); + checkNotNull(destination); + checkNotNull(to); + checkNotNull(transform); + this.source = source; + this.from = from.toBlockVector3(); + this.destination = destination; + this.to = to.toBlockVector3(); + this.transform = transform; + } + + /** + * Make a new biome copy. + * + * @param source the source extent + * @param from the source offset + * @param destination the destination extent + * @param to the destination offset + * @param transform a transform to apply to positions (after source offset, before destination offset) + */ + public ExtentBiomeCopy(Extent source, BlockVector3 from, Extent destination, BlockVector3 to, Transform transform) { + checkNotNull(source); + checkNotNull(from); + checkNotNull(destination); + checkNotNull(to); + checkNotNull(transform); + this.source = source; + this.from = from; + this.destination = destination; + this.to = to; + this.transform = transform; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + BiomeType biome = source.getBiome(position); + BlockVector3 orig = position.subtract(from); + BlockVector3 transformed = transform.apply(orig.toVector3()) + .toBlockPoint() + .add(to); + + return destination.setBiome(transformed, biome); + } + + @Override + @Deprecated + public boolean apply(BlockVector2 position) throws WorldEditException { + boolean success = false; + for (int y = destination.getMinimumPoint().getY(); y <= destination.getMaximumPoint().getY(); y++) { + success |= apply(position.toBlockVector3(y)); + } + return success; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/block/BlockDistributionCounter.java b/src/main/java/com/sk89q/worldedit/function/block/BlockDistributionCounter.java new file mode 100644 index 0000000..4182e7c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/BlockDistributionCounter.java @@ -0,0 +1,72 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.block; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.world.block.BlockState; + +import java.util.*; + +public class BlockDistributionCounter implements RegionFunction { + + private final Extent extent; + private final boolean separateStates; + + private final List> distribution = new ArrayList<>(); + private final Map> map = new HashMap<>(); + + public BlockDistributionCounter(Extent extent, boolean separateStates) { + this.extent = extent; + this.separateStates = separateStates; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + BlockState blk = extent.getBlock(position); + if (!separateStates) { + blk = blk.getBlockType().getDefaultState(); + } + + if (map.containsKey(blk)) { + map.get(blk).increment(); + } else { + Countable c = new Countable<>(blk, 1); + map.put(blk, c); + distribution.add(c); + } + + return true; + } + + /** + * Gets the distribution list. + * + * @return The distribution + */ + public List> getDistribution() { + Collections.sort(distribution); + Collections.reverse(distribution); + return this.distribution; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/block/BlockReplace.java b/src/main/java/com/sk89q/worldedit/function/block/BlockReplace.java new file mode 100644 index 0000000..5543205 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/BlockReplace.java @@ -0,0 +1,56 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.block; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Replaces blocks with a given pattern. + */ +public class BlockReplace implements RegionFunction { + + private final Extent extent; + private final Pattern pattern; + + /** + * Create a new instance. + * + * @param extent an extent + * @param pattern a pattern + */ + public BlockReplace(Extent extent, Pattern pattern) { + checkNotNull(extent); + checkNotNull(pattern); + this.extent = extent; + this.pattern = pattern; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + return extent.setBlock(position, pattern.applyBlock(position)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/block/Counter.java b/src/main/java/com/sk89q/worldedit/function/block/Counter.java new file mode 100644 index 0000000..4acee95 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/Counter.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.block; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.BlockVector3; + +/** + * Keeps a count of the number of times that {@link #apply(BlockVector3)} is + * called. + */ +public class Counter implements RegionFunction { + + private int count; + + /** + * Returns the number of blocks that have been counted. + * + * @return the number of blocks + */ + public int getCount() { + return count; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + count++; + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java b/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java new file mode 100644 index 0000000..7f56aed --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java @@ -0,0 +1,117 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.block; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.CompoundTagBuilder; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.internal.helper.MCDirections; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Direction.Flag; +import com.sk89q.worldedit.world.block.BaseBlock; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Copies blocks from one extent to another. + */ +public class ExtentBlockCopy implements RegionFunction { + + private final Extent source; + private final Extent destination; + private final BlockVector3 from; + private final BlockVector3 to; + private final Transform transform; + + /** + * Make a new copy. + * + * @param source the source extent + * @param from the source offset + * @param destination the destination extent + * @param to the destination offset + * @param transform a transform to apply to positions (after source offset, before destination offset) + */ + public ExtentBlockCopy(Extent source, BlockVector3 from, Extent destination, BlockVector3 to, Transform transform) { + checkNotNull(source); + checkNotNull(from); + checkNotNull(destination); + checkNotNull(to); + checkNotNull(transform); + this.source = source; + this.from = from; + this.destination = destination; + this.to = to; + this.transform = transform; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + BaseBlock block = source.getFullBlock(position); + BlockVector3 orig = position.subtract(from); + BlockVector3 transformed = transform.apply(orig.toVector3()).toBlockPoint(); + + // Apply transformations to NBT data if necessary + block = transformNbtData(block); + + return destination.setBlock(transformed.add(to), block); + } + + /** + * Transform NBT data in the given block state and return a new instance + * if the NBT data needs to be transformed. + * + * @param state the existing state + * @return a new state or the existing one + */ + private BaseBlock transformNbtData(BaseBlock state) { + CompoundTag tag = state.getNbtData(); + + if (tag != null) { + // Handle blocks which store their rotation in NBT + if (tag.containsKey("Rot")) { + int rot = tag.asInt("Rot"); + + Direction direction = MCDirections.fromRotation(rot); + + if (direction != null) { + Vector3 vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector3.ZERO)).normalize(); + Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL | Flag.ORDINAL | Flag.SECONDARY_ORDINAL); + + if (newDirection != null) { + CompoundTagBuilder builder = tag.createBuilder(); + + builder.putByte("Rot", (byte) MCDirections.toRotation(newDirection)); + + return state.toBaseBlock(builder.build()); + } + } + } + } + + return state; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java b/src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java new file mode 100644 index 0000000..29aad9c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java @@ -0,0 +1,103 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.block; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.LayerFunction; +import com.sk89q.worldedit.function.mask.BlockTypeMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Makes a layer of grass on top, three layers of dirt below, and smooth stone + * only below that for all layers that originally consist of grass, dirt, + * or smooth stone. + */ +public class Naturalizer implements LayerFunction { + + private final EditSession editSession; + private final Mask mask; + private int affected = 0; + + /** + * Make a new naturalizer. + * + * @param editSession an edit session + */ + public Naturalizer(EditSession editSession) { + checkNotNull(editSession); + this.editSession = editSession; + this.mask = new BlockTypeMask(editSession, BlockTypes.GRASS_BLOCK, BlockTypes.DIRT, BlockTypes.STONE); + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public boolean isGround(BlockVector3 position) { + return mask.test(position); + } + + private BlockState getTargetBlock(int depth) { + switch (depth) { + case 0: + return BlockTypes.GRASS_BLOCK.getDefaultState(); + case 1: + case 2: + case 3: + return BlockTypes.DIRT.getDefaultState(); + default: + return BlockTypes.STONE.getDefaultState(); + } + } + + private boolean naturalize(BlockVector3 position, int depth) throws WorldEditException { + BlockState block = editSession.getBlock(position); + BlockState targetBlock = getTargetBlock(depth); + + if (block.equalsFuzzy(targetBlock)) { + return false; + } + + return editSession.setBlock(position, targetBlock); + } + + @Override + public boolean apply(BlockVector3 position, int depth) throws WorldEditException { + if (mask.test(position)) { + if (naturalize(position, depth)) { + ++affected; + } + } + + return true; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java b/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java new file mode 100644 index 0000000..17e13f8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java @@ -0,0 +1,138 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.block; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.LayerFunction; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +public class SnowSimulator implements LayerFunction { + + private final BlockState ice = BlockTypes.ICE.getDefaultState(); + private final BlockState snow = BlockTypes.SNOW.getDefaultState(); + private final BlockState snowBlock = BlockTypes.SNOW_BLOCK.getDefaultState(); + + private final Property snowLayersProperty = BlockTypes.SNOW.getProperty("layers"); + private final Property waterLevelProperty = BlockTypes.WATER.getProperty("level"); + + private final Extent extent; + private final World world; + private final boolean stack; + + private int affected; + + public SnowSimulator(Extent extent, boolean stack) { + if (extent instanceof World) { + this.world = (World) extent; + } else if (extent instanceof EditSession && ((EditSession) extent).getWorld() != null) { + this.world = ((EditSession) extent).getWorld(); + } else { + throw new IllegalArgumentException("extent must be a world or EditSession with a world"); + } + + this.extent = extent; + this.stack = stack; + + this.affected = 0; + } + + public int getAffected() { + return this.affected; + } + + @Override + public boolean isGround(BlockVector3 position) { + BlockState block = this.extent.getBlock(position); + + // We're returning the first block we can place *on top of* + if (block.getBlockType().getMaterial().isAir() || (stack && block.getBlockType() == BlockTypes.SNOW)) { + return false; + } + + // Unless it's water + if (block.getBlockType() == BlockTypes.WATER) { + return true; + } + + // Stop searching when we hit a movement blocker + return block.getBlockType().getMaterial().isMovementBlocker(); + } + + @Override + public boolean apply(BlockVector3 position, int depth) throws WorldEditException { + if (depth > 0) { + // We only care about the first layer. + return false; + } + + BlockState block = this.extent.getBlock(position); + + if (block.getBlockType() == BlockTypes.WATER) { + if (block.getState(waterLevelProperty) == 0) { + if (this.extent.setBlock(position, ice)) { + affected++; + } + } + return false; + } + + // Can't put snow this far up + if (position.getBlockY() == this.extent.getMaximumPoint().getBlockY()) { + return false; + } + + BlockVector3 abovePosition = position.add(0, 1, 0); + BlockState above = this.extent.getBlock(abovePosition); + + // Can only replace air (or snow in stack mode) + if (!above.getBlockType().getMaterial().isAir() && (!stack || above.getBlockType() != BlockTypes.SNOW)) { + return false; + } + + if (stack && above.getBlockType() == BlockTypes.SNOW) { + int currentHeight = above.getState(snowLayersProperty); + // We've hit the highest layer (If it doesn't contain current + 2 it means it's 1 away from full) + if (!snowLayersProperty.getValues().contains(currentHeight + 2)) { + if (this.extent.setBlock(abovePosition, snowBlock)) { + this.affected++; + } + } else { + if (this.extent.setBlock(abovePosition, above.with(snowLayersProperty, currentHeight + 1))) { + this.affected++; + } + } + return false; + } + + if (!this.world.canPlaceAt(abovePosition, snow)) { + return false; + } + if (this.extent.setBlock(abovePosition, snow)) { + this.affected++; + } + return false; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java b/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java new file mode 100644 index 0000000..0a21244 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java @@ -0,0 +1,192 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.entity; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.CompoundTagBuilder; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.EntityFunction; +import com.sk89q.worldedit.internal.helper.MCDirections; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Direction.Flag; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.entity.EntityTypes; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Copies entities provided to the function to the provided destination + * {@code Extent}. + */ +public class ExtentEntityCopy implements EntityFunction { + + private final Extent destination; + private final Vector3 from; + private final Vector3 to; + private final Transform transform; + private boolean removing; + + /** + * Create a new instance. + * + * @param from the from position + * @param destination the destination {@code Extent} + * @param to the destination position + * @param transform the transformation to apply to both position and orientation + */ + public ExtentEntityCopy(Vector3 from, Extent destination, Vector3 to, Transform transform) { + checkNotNull(from); + checkNotNull(destination); + checkNotNull(to); + checkNotNull(transform); + this.destination = destination; + this.from = from; + this.to = to; + this.transform = transform; + } + + /** + * Return whether entities that are copied should be removed. + * + * @return true if removing + */ + public boolean isRemoving() { + return removing; + } + + /** + * Set whether entities that are copied should be removed. + * + * @param removing true if removing + */ + public void setRemoving(boolean removing) { + this.removing = removing; + } + + @Override + public boolean apply(Entity entity) throws WorldEditException { + BaseEntity state = entity.getState(); + if (state != null) { + Location newLocation; + Location location = entity.getLocation(); + // If the entity has stored the location in the NBT data, we use that location + CompoundTag tag = state.getNbtData(); + boolean hasTilePosition = tag != null && tag.containsKey("TileX") && tag.containsKey("TileY") && tag.containsKey("TileZ"); + if (hasTilePosition) { + location = location.setPosition(Vector3.at(tag.asInt("TileX"), tag.asInt("TileY"), tag.asInt("TileZ")).add(0.5, 0.5, 0.5)); + } + + Vector3 pivot = from.round().add(0.5, 0.5, 0.5); + Vector3 newPosition = transform.apply(location.toVector().subtract(pivot)); + if (hasTilePosition) { + newPosition = newPosition.subtract(0.5, 0.5, 0.5); + } + Vector3 newDirection; + + newDirection = transform.isIdentity() + ? entity.getLocation().getDirection() + : transform.apply(location.getDirection()).subtract(transform.apply(Vector3.ZERO)).normalize(); + newLocation = new Location(destination, newPosition.add(to.round().add(0.5, 0.5, 0.5)), newDirection); + + // Some entities store their position data in NBT + state = transformNbtData(state); + + boolean success = destination.createEntity(newLocation, state) != null; + + // Remove + if (isRemoving() && success) { + entity.remove(); + } + + return success; + } else { + return false; + } + } + + /** + * Transform NBT data in the given entity state and return a new instance + * if the NBT data needs to be transformed. + * + * @param state the existing state + * @return a new state or the existing one + */ + private BaseEntity transformNbtData(BaseEntity state) { + CompoundTag tag = state.getNbtData(); + + if (tag != null) { + // Handle leashed entities + Tag leashTag = tag.getValue().get("Leash"); + if (leashTag instanceof CompoundTag) { + CompoundTag leashCompound = (CompoundTag) leashTag; + if (leashCompound.containsKey("X")) { // leashed to a fence + Vector3 tilePosition = Vector3.at(leashCompound.asInt("X"), leashCompound.asInt("Y"), leashCompound.asInt("Z")); + BlockVector3 newLeash = transform.apply(tilePosition.subtract(from)).add(to).toBlockPoint(); + return new BaseEntity(state.getType(), tag.createBuilder() + .put("Leash", leashCompound.createBuilder() + .putInt("X", newLeash.getBlockX()) + .putInt("Y", newLeash.getBlockY()) + .putInt("Z", newLeash.getBlockZ()) + .build() + ).build()); + } + } + + // Handle hanging entities (paintings, item frames, etc.) + boolean hasTilePosition = tag.containsKey("TileX") && tag.containsKey("TileY") && tag.containsKey("TileZ"); + boolean hasFacing = tag.containsKey("Facing"); + + if (hasTilePosition) { + Vector3 tilePosition = Vector3.at(tag.asInt("TileX"), tag.asInt("TileY"), tag.asInt("TileZ")); + BlockVector3 newTilePosition = transform.apply(tilePosition.subtract(from)).add(to).toBlockPoint(); + + CompoundTagBuilder builder = tag.createBuilder() + .putInt("TileX", newTilePosition.getBlockX()) + .putInt("TileY", newTilePosition.getBlockY()) + .putInt("TileZ", newTilePosition.getBlockZ()); + + if (hasFacing) { + boolean isPainting = state.getType() == EntityTypes.PAINTING; // Paintings have different facing values + Direction direction = isPainting ? MCDirections.fromHorizontalHanging(tag.asInt("Facing")) : MCDirections.fromHanging(tag.asInt("Facing")); + + if (direction != null) { + Vector3 vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector3.ZERO)).normalize(); + Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL); + + if (newDirection != null) { + builder.putByte("Facing", (byte) (isPainting ? MCDirections.toHorizontalHanging(newDirection) : MCDirections.toHanging(newDirection))); + } + } + } + + return new BaseEntity(state.getType(), builder.build()); + } + } + + return state; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/factory/Apply.java b/src/main/java/com/sk89q/worldedit/function/factory/Apply.java new file mode 100644 index 0000000..baee779 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/factory/Apply.java @@ -0,0 +1,66 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.factory; + +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.regions.NullRegion; +import com.sk89q.worldedit.regions.Region; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; + +/** + * Creates an operation from a region context. + * + * @deprecated Use {@link ApplyRegion} or {@link ApplyLayer} + * depending on function type. + */ +@Deprecated +public class Apply implements Contextual { + + private final Region region; + private final Contextual function; + + public Apply(Contextual function) { + this(new NullRegion(), function); + } + + public Apply(Region region, Contextual function) { + checkNotNull(region, "region"); + checkNotNull(function, "function"); + this.region = region; + this.function = function; + } + + @Override + public Operation createFromContext(EditContext context) { + return new RegionVisitor(firstNonNull(context.getRegion(), region), function.createFromContext(context)); + } + + @Override + public String toString() { + return "set " + function; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/factory/ApplyLayer.java b/src/main/java/com/sk89q/worldedit/function/factory/ApplyLayer.java new file mode 100644 index 0000000..d1ad479 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/factory/ApplyLayer.java @@ -0,0 +1,65 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.factory; + +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.LayerFunction; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.visitor.LayerVisitor; +import com.sk89q.worldedit.regions.FlatRegion; +import com.sk89q.worldedit.regions.NullRegion; +import com.sk89q.worldedit.regions.Regions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; + +public class ApplyLayer implements Contextual { + + private final FlatRegion region; + private final Contextual function; + + public ApplyLayer(Contextual function) { + this(Regions.asFlatRegion(new NullRegion()), function); + } + + public ApplyLayer(FlatRegion region, Contextual function) { + checkNotNull(region, "region"); + checkNotNull(function, "function"); + this.region = region; + this.function = function; + } + + @Override + public Operation createFromContext(EditContext context) { + FlatRegion localRegion = Regions.asFlatRegion(firstNonNull(context.getRegion(), region)); + + return new LayerVisitor(localRegion, + localRegion.getMinimumPoint().getY(), + localRegion.getMaximumPoint().getY(), + function.createFromContext(context)); + } + + @Override + public String toString() { + return "set " + function; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/factory/ApplyRegion.java b/src/main/java/com/sk89q/worldedit/function/factory/ApplyRegion.java new file mode 100644 index 0000000..3b51a65 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/factory/ApplyRegion.java @@ -0,0 +1,59 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.factory; + +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.regions.NullRegion; +import com.sk89q.worldedit.regions.Region; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; + +public class ApplyRegion implements Contextual { + + private final Region region; + private final Contextual function; + + public ApplyRegion(Contextual function) { + this(new NullRegion(), function); + } + + public ApplyRegion(Region region, Contextual function) { + checkNotNull(region, "region"); + checkNotNull(function, "function"); + this.region = region; + this.function = function; + } + + @Override + public Operation createFromContext(EditContext context) { + return new RegionVisitor(firstNonNull(context.getRegion(), region), function.createFromContext(context)); + } + + @Override + public String toString() { + return "set " + function; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/factory/BiomeFactory.java b/src/main/java/com/sk89q/worldedit/function/factory/BiomeFactory.java new file mode 100644 index 0000000..bd0d955 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/factory/BiomeFactory.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.factory; + +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.biome.BiomeReplace; +import com.sk89q.worldedit.function.pattern.BiomePattern; + +public class BiomeFactory implements Contextual { + + private final BiomePattern biomeType; + + public BiomeFactory(BiomePattern biomeType) { + this.biomeType = biomeType; + } + + @Override + public RegionFunction createFromContext(EditContext context) { + return new BiomeReplace(context.getDestination(), this.biomeType); + } + + @Override + public String toString() { + return "set biome"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/factory/Deform.java b/src/main/java/com/sk89q/worldedit/function/factory/Deform.java new file mode 100644 index 0000000..dad6a65 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/factory/Deform.java @@ -0,0 +1,207 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.factory; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.NullExtent; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.NullRegion; +import com.sk89q.worldedit.regions.Region; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; + +public class Deform implements Contextual { + + private Extent destination; + private Region region; + private final Expression expression; + private Mode mode; + private Vector3 offset = Vector3.ZERO; + + public Deform(String expression) { + this(new NullExtent(), new NullRegion(), expression); + } + + public Deform(String expression, Mode mode) { + this(new NullExtent(), new NullRegion(), expression, mode); + } + + public Deform(Extent destination, Region region, String expression) { + this(destination, region, expression, Mode.UNIT_CUBE); + } + + public Deform(Extent destination, Region region, String expression, Mode mode) { + checkNotNull(destination, "destination"); + checkNotNull(region, "region"); + checkNotNull(mode, "mode"); + checkNotNull(expression, "expression"); + this.expression = Expression.compile(expression, "x", "y", "z"); + this.expression.optimize(); + this.destination = destination; + this.region = region; + this.mode = mode; + } + + public Extent getDestination() { + return destination; + } + + public void setDestination(Extent destination) { + checkNotNull(destination, "destination"); + this.destination = destination; + } + + public Region getRegion() { + return region; + } + + public void setRegion(Region region) { + checkNotNull(region, "region"); + this.region = region; + } + + public Mode getMode() { + return mode; + } + + public void setMode(Mode mode) { + checkNotNull(mode, "mode"); + this.mode = mode; + } + + public Vector3 getOffset() { + return offset; + } + + public void setOffset(Vector3 offset) { + checkNotNull(offset, "offset"); + this.offset = offset; + } + + @Override + public String toString() { + return "deformation of " + expression.getSource(); + } + + @Override + public Operation createFromContext(final EditContext context) { + final Vector3 zero; + Vector3 unit; + + Region region = firstNonNull(context.getRegion(), this.region); + + switch (mode) { + case UNIT_CUBE: + final Vector3 min = region.getMinimumPoint().toVector3(); + final Vector3 max = region.getMaximumPoint().toVector3(); + + zero = max.add(min).multiply(0.5); + unit = max.subtract(zero); + + if (unit.getX() == 0) { + unit = unit.withX(1.0); + } + if (unit.getY() == 0) { + unit = unit.withY(1.0); + } + if (unit.getZ() == 0) { + unit = unit.withZ(1.0); + } + break; + case RAW_COORD: + zero = Vector3.ZERO; + unit = Vector3.ONE; + break; + case OFFSET: + default: + zero = offset; + unit = Vector3.ONE; + } + + LocalSession session = context.getSession(); + return new DeformOperation(context.getDestination(), region, zero, unit, expression, + session == null ? WorldEdit.getInstance().getConfiguration().calculationTimeout : session.getTimeout()); + } + + private static final class DeformOperation implements Operation { + private final Extent destination; + private final Region region; + private final Vector3 zero; + private final Vector3 unit; + private final Expression expression; + private final int timeout; + + private DeformOperation(Extent destination, Region region, Vector3 zero, Vector3 unit, Expression expression, + int timeout) { + this.destination = destination; + this.region = region; + this.zero = zero; + this.unit = unit; + this.expression = expression; + this.timeout = timeout; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + try { + // TODO: Move deformation code + ((EditSession) destination).deformRegion(region, zero, unit, expression, timeout); + return null; + } catch (ExpressionException e) { + throw new RuntimeException("Failed to execute expression", e); // TODO: Better exception to throw here? + } + } + + @Override + public void cancel() { + } + + + @Override + public Iterable getStatusMessages() { + return ImmutableList.of(TranslatableComponent.of("worldedit.operation.deform.expression", + TextComponent.of(expression.getSource()).color(TextColor.LIGHT_PURPLE))); + } + + } + + public enum Mode { + RAW_COORD, + OFFSET, + UNIT_CUBE + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/factory/Paint.java b/src/main/java/com/sk89q/worldedit/function/factory/Paint.java new file mode 100644 index 0000000..f53fcce --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/factory/Paint.java @@ -0,0 +1,79 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.factory; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.NullExtent; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.GroundFunction; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.NoiseFilter2D; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.visitor.LayerVisitor; +import com.sk89q.worldedit.math.noise.RandomNoise; +import com.sk89q.worldedit.regions.NullRegion; +import com.sk89q.worldedit.regions.Region; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.regions.Regions.*; +import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; + +public class Paint implements Contextual { + + private final Extent destination; + private final Region region; + private final Contextual function; + private final double density; + + public Paint(Contextual function, double density) { + this(new NullExtent(), new NullRegion(), function, density); + } + + public Paint(Extent destination, Region region, Contextual function, + double density) { + checkNotNull(destination, "destination"); + checkNotNull(region, "region"); + checkNotNull(function, "function"); + checkNotNull(density, "density"); + this.destination = destination; + this.region = region; + this.function = function; + this.density = density; + new NoiseFilter2D(new RandomNoise(), density); // Check validity of the density argument + } + + @Override + public Operation createFromContext(EditContext context) { + Extent destination = firstNonNull(context.getDestination(), this.destination); + Region region = firstNonNull(context.getRegion(), this.region); + GroundFunction ground = new GroundFunction(new ExistingBlockMask(destination), function.createFromContext(context)); + LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + return visitor; + } + + @Override + public String toString() { + return "scatter " + function; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/factory/Snow.java b/src/main/java/com/sk89q/worldedit/function/factory/Snow.java new file mode 100644 index 0000000..0f09b54 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/factory/Snow.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.factory; + +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.LayerFunction; +import com.sk89q.worldedit.function.block.SnowSimulator; + +public class Snow implements Contextual { + + private final boolean stack; + + public Snow(boolean stack) { + this.stack = stack; + } + + @Override + public LayerFunction createFromContext(EditContext context) { + return new SnowSimulator(context.getDestination(), this.stack); + } + + @Override + public String toString() { + return "snow" + (this.stack ? " stacker" : ""); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java b/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java new file mode 100644 index 0000000..d199fcb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java @@ -0,0 +1,119 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.generator; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomPattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +/** + * Generates flora (which may include tall grass, flowers, etc.). + * + *

The current implementation is not biome-aware, but it may become so in + * the future.

+ */ +public class FloraGenerator implements RegionFunction { + + private final EditSession editSession; + private final boolean biomeAware = false; + private final Pattern desertPattern = getDesertPattern(); + private final Pattern temperatePattern = getTemperatePattern(); + + /** + * Create a new flora generator. + * + * @param editSession the edit session + */ + public FloraGenerator(EditSession editSession) { + this.editSession = editSession; + } + + /** + * Return whether the flora generator is set to be biome-aware. + * + *

By default, it is currently disabled by default, but + * this may change.

+ * + * @return true if biome aware + */ + public boolean isBiomeAware() { + return biomeAware; + } + + /** + * Set whether the generator is biome aware. + * + *

It is currently not possible to make the generator biome-aware.

+ * + * @param biomeAware must always be false + */ + public void setBiomeAware(boolean biomeAware) { + if (biomeAware) { + throw new IllegalArgumentException("Cannot enable biome-aware mode; not yet implemented"); + } + } + + /** + * Get a pattern for plants to place inside a desert environment. + * + * @return a pattern that places flora + */ + public static Pattern getDesertPattern() { + RandomPattern pattern = new RandomPattern(); + pattern.add(BlockTypes.DEAD_BUSH.getDefaultState(), 30); + pattern.add(BlockTypes.CACTUS.getDefaultState(), 20); + pattern.add(BlockTypes.AIR.getDefaultState(), 300); + return pattern; + } + + /** + * Get a pattern for plants to place inside a temperate environment. + * + * @return a pattern that places flora + */ + public static Pattern getTemperatePattern() { + RandomPattern pattern = new RandomPattern(); + pattern.add(BlockTypes.GRASS.getDefaultState(), 300); + pattern.add(BlockTypes.POPPY.getDefaultState(), 5); + pattern.add(BlockTypes.DANDELION.getDefaultState(), 5); + return pattern; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + BlockState block = editSession.getBlock(position); + + if (block.getBlockType() == BlockTypes.GRASS_BLOCK) { + editSession.setBlock(position.add(0, 1, 0), temperatePattern.applyBlock(position)); + return true; + } else if (block.getBlockType() == BlockTypes.SAND) { + editSession.setBlock(position.add(0, 1, 0), desertPattern.applyBlock(position)); + return true; + } + + return false; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java b/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java new file mode 100644 index 0000000..e502615 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java @@ -0,0 +1,74 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.generator; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +/** + * Generates forests by searching for the ground starting from the given upper Y + * coordinate for every column given. + */ +public class ForestGenerator implements RegionFunction { + + private final TreeGenerator.TreeType treeType; + private final EditSession editSession; + + /** + * Create a new instance. + * + * @param editSession the edit session + * @param treeType a tree generator + */ + public ForestGenerator(EditSession editSession, TreeGenerator.TreeType treeType) { + this.editSession = editSession; + this.treeType = treeType; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + BlockState block = editSession.getBlock(position); + BlockType t = block.getBlockType(); + + if (t.getMaterial().isSolid()) { + return treeType.generate(editSession, position.add(0, 1, 0)); + } else if (t.getMaterial().isReplacedDuringPlacement()) { + // since the implementation's tree generators generally don't generate in non-air spots, + // we trick editsession history here in the first call + editSession.setBlock(position, BlockTypes.AIR.getDefaultState()); + // and then trick the generator here by directly setting into the world + editSession.getWorld().setBlock(position, BlockTypes.AIR.getDefaultState()); + // so that now the generator can generate the tree + boolean success = treeType.generate(editSession, position); + if (!success) { + editSession.setBlock(position, block); // restore on failure + } + return success; + } else { // Trees won't grow on this! + return false; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java b/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java new file mode 100644 index 0000000..a9c0703 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java @@ -0,0 +1,215 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.generator; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Random; + +/** + * Generates patches of fruit (i.e. pumpkin patches). + */ +public class GardenPatchGenerator implements RegionFunction { + + private final Random random = new Random(); + private final EditSession editSession; + private Pattern plant = getPumpkinPattern(); + private final Pattern leafPattern = BlockTypes.OAK_LEAVES.getDefaultState().with(BlockTypes.OAK_LEAVES.getProperty("persistent"), true); + private int affected; + + /** + * Create a new instance. + * + * @param editSession the edit session + */ + public GardenPatchGenerator(EditSession editSession) { + this.editSession = editSession; + } + + /** + * Get the plant pattern that is placed. + * + * @return the plant pattern + */ + public Pattern getPlant() { + return plant; + } + + /** + * Set the plant pattern that is placed. + * + * @param plant the plant pattern + */ + public void setPlant(Pattern plant) { + this.plant = plant; + } + + /** + * Get the number of affected blocks. + * + * @return affected count + */ + public int getAffected() { + return affected; + } + + /** + * Make a patch vine. + * + * @param basePos the base position + * @param pos the vine position + */ + private void placeVine(BlockVector3 basePos, BlockVector3 pos) throws MaxChangedBlocksException { + if (pos.distance(basePos) > 4) { + return; + } + if (!editSession.getBlock(pos).getBlockType().getMaterial().isAir()) { + return; + } + + for (int i = -1; i > -3; --i) { + BlockVector3 testPos = pos.add(0, i, 0); + if (editSession.getBlock(testPos).getBlockType().getMaterial().isAir()) { + pos = testPos; + } else { + break; + } + } + + setBlockIfAir(editSession, pos, leafPattern); + affected++; + + int t = random.nextInt(4); + int h = random.nextInt(3) - 1; + BlockVector3 p; + + BlockState log = BlockTypes.OAK_LOG.getDefaultState(); + + switch (t) { + case 0: + if (random.nextBoolean()) { + placeVine(basePos, pos.add(1, 0, 0)); + } + if (random.nextBoolean()) { + setBlockIfAir(editSession, pos.add(1, h, -1), log); + affected++; + } + setBlockIfAir(editSession, p = pos.add(0, 0, -1), plant.applyBlock(p)); + affected++; + break; + + case 1: + if (random.nextBoolean()) { + placeVine(basePos, pos.add(0, 0, 1)); + } + if (random.nextBoolean()) { + setBlockIfAir(editSession, pos.add(1, h, 0), log); + affected++; + } + setBlockIfAir(editSession, p = pos.add(1, 0, 1), plant.applyBlock(p)); + affected++; + break; + + case 2: + if (random.nextBoolean()) { + placeVine(basePos, pos.add(0, 0, -1)); + } + if (random.nextBoolean()) { + setBlockIfAir(editSession, pos.add(-1, h, 0), log); + affected++; + } + setBlockIfAir(editSession, p = pos.add(-1, 0, 1), plant.applyBlock(p)); + affected++; + break; + + case 3: + if (random.nextBoolean()) { + placeVine(basePos, pos.add(-1, 0, 0)); + } + if (random.nextBoolean()) { + setBlockIfAir(editSession, pos.add(-1, h, -1), log); + affected++; + } + setBlockIfAir(editSession, p = pos.add(-1, 0, -1), plant.applyBlock(p)); + affected++; + break; + default: + break; + } + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + if (!editSession.getBlock(position).getBlockType().getMaterial().isAir()) { + position = position.add(0, 1, 0); + } + + if (!editSession.getBlock(position.add(0, -1, 0)).getBlockType().equals(BlockTypes.GRASS_BLOCK)) { + return false; + } + + + setBlockIfAir(editSession, position, leafPattern); + + placeVine(position, position.add(0, 0, 1)); + placeVine(position, position.add(0, 0, -1)); + placeVine(position, position.add(1, 0, 0)); + placeVine(position, position.add(-1, 0, 0)); + + return true; + } + + /** + * Get a pattern that creates pumpkins with different faces. + * + * @return a pumpkin pattern + */ + public static Pattern getPumpkinPattern() { + return BlockTypes.PUMPKIN.getDefaultState(); + } + + /** + * Set a block only if there's no block already there. + * + * @param position the position + * @param pattern the pattern to set + * @return if block was changed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + private static boolean setBlockIfAir(EditSession session, BlockVector3 position, Pattern pattern) throws MaxChangedBlocksException { + return session.getBlock(position).getBlockType().getMaterial().isAir() && session.setBlock(position, pattern); + } + + /** + * Get a pattern that creates melons. + * + * @return a melon pattern + */ + public static Pattern getMelonPattern() { + return BlockTypes.MELON.getDefaultState(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java b/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java new file mode 100644 index 0000000..b688daa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.extent.Extent; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An abstract implementation of {@link Mask} that takes uses an {@link Extent}. + */ +public abstract class AbstractExtentMask extends AbstractMask { + + private Extent extent; + + /** + * Construct a new mask. + * + * @param extent the extent + */ + protected AbstractExtentMask(Extent extent) { + setExtent(extent); + } + + /** + * Get the extent. + * + * @return the extent + */ + public Extent getExtent() { + return extent; + } + + /** + * Set the extent. + * + * @param extent the extent + */ + public void setExtent(Extent extent) { + checkNotNull(extent); + this.extent = extent; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask.java b/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask.java new file mode 100644 index 0000000..adb9f38 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +/** + * A base class of {@link Mask} that all masks should inherit from. + */ +public abstract class AbstractMask implements Mask { +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask2D.java b/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask2D.java new file mode 100644 index 0000000..d00a78f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask2D.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +/** + * A base class of {@link Mask2D} that all masks should inherit from. + */ +public abstract class AbstractMask2D implements Mask2D { +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java b/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java new file mode 100644 index 0000000..8f6415d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java @@ -0,0 +1,105 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Tests true if the biome at applied points is the same as the one given. + */ +public class BiomeMask extends AbstractMask { + + private final Extent extent; + private final Set biomes = new HashSet<>(); + + /** + * Create a new biome mask. + * + * @param extent the extent + * @param biomes a list of biomes to match + */ + public BiomeMask(Extent extent, Collection biomes) { + checkNotNull(extent); + checkNotNull(biomes); + this.extent = extent; + this.biomes.addAll(biomes); + } + + /** + * Create a new biome mask. + * + * @param extent the extent + * @param biome an array of biomes to match + */ + public BiomeMask(Extent extent, BiomeType... biome) { + this(extent, Arrays.asList(checkNotNull(biome))); + } + + /** + * Add the given biomes to the list of criteria. + * + * @param biomes a list of biomes + */ + public void add(Collection biomes) { + checkNotNull(biomes); + this.biomes.addAll(biomes); + } + + /** + * Add the given biomes to the list of criteria. + * + * @param biome an array of biomes + */ + public void add(BiomeType... biome) { + add(Arrays.asList(checkNotNull(biome))); + } + + /** + * Get the list of biomes that are tested with. + * + * @return a list of biomes + */ + public Collection getBiomes() { + return biomes; + } + + @Override + public boolean test(BlockVector3 vector) { + BiomeType biome = extent.getBiome(vector); + return biomes.contains(biome); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask2D.java b/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask2D.java new file mode 100644 index 0000000..5df46fa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask2D.java @@ -0,0 +1,101 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.world.biome.BiomeType; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Tests true if the biome at applied points is the same as the one given. + * + * @deprecated use {@link BiomeMask} as biomes are now 3D. + */ +@Deprecated +public class BiomeMask2D extends AbstractMask2D { + + private final Extent extent; + private final Set biomes = new HashSet<>(); + + /** + * Create a new biome mask. + * + * @param extent the extent + * @param biomes a list of biomes to match + */ + public BiomeMask2D(Extent extent, Collection biomes) { + checkNotNull(extent); + checkNotNull(biomes); + this.extent = extent; + this.biomes.addAll(biomes); + } + + /** + * Create a new biome mask. + * + * @param extent the extent + * @param biome an array of biomes to match + */ + public BiomeMask2D(Extent extent, BiomeType... biome) { + this(extent, Arrays.asList(checkNotNull(biome))); + } + + /** + * Add the given biomes to the list of criteria. + * + * @param biomes a list of biomes + */ + public void add(Collection biomes) { + checkNotNull(biomes); + this.biomes.addAll(biomes); + } + + /** + * Add the given biomes to the list of criteria. + * + * @param biome an array of biomes + */ + public void add(BiomeType... biome) { + add(Arrays.asList(checkNotNull(biome))); + } + + /** + * Get the list of biomes that are tested with. + * + * @return a list of biomes + */ + public Collection getBiomes() { + return biomes; + } + + @Override + public boolean test(BlockVector2 vector) { + BiomeType biome = extent.getBiome(vector); + return biomes.contains(biome); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java b/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java new file mode 100644 index 0000000..2479b96 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockCategory; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that tests whether a block matches a given {@link BlockCategory}, or tag. + */ +public class BlockCategoryMask extends AbstractExtentMask { + + private final BlockCategory category; + + public BlockCategoryMask(Extent extent, BlockCategory category) { + super(extent); + checkNotNull(category); + this.category = category; + } + + @Override + public boolean test(BlockVector3 vector) { + return category.contains(getExtent().getBlock(vector)); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java b/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java new file mode 100644 index 0000000..55206c3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java @@ -0,0 +1,114 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that checks whether blocks at the given positions are matched by + * a block in a list. + * + *

This mask checks for both an exact block type and state value match, + * respecting fuzzy status of the BlockState.

+ */ +public class BlockMask extends AbstractExtentMask { + + private final Set blocks = new HashSet<>(); + + /** + * Create a new block mask. + * + * @param extent the extent + * @param blocks a list of blocks to match + */ + public BlockMask(Extent extent, Collection blocks) { + super(extent); + checkNotNull(blocks); + this.blocks.addAll(blocks); + } + + /** + * Create a new block mask. + * + * @param extent the extent + * @param block an array of blocks to match + */ + public BlockMask(Extent extent, BaseBlock... block) { + this(extent, Arrays.asList(checkNotNull(block))); + } + + /** + * Add the given blocks to the list of criteria. + * + * @param blocks a list of blocks + */ + public void add(Collection blocks) { + checkNotNull(blocks); + this.blocks.addAll(blocks); + } + + /** + * Add the given blocks to the list of criteria. + * + * @param block an array of blocks + */ + public void add(BaseBlock... block) { + add(Arrays.asList(checkNotNull(block))); + } + + /** + * Get the list of blocks that are tested with. + * + * @return a list of blocks + */ + public Collection getBlocks() { + return blocks; + } + + @Override + public boolean test(BlockVector3 vector) { + BlockState block = getExtent().getBlock(vector); + for (BaseBlock testBlock : blocks) { + if (testBlock.equalsFuzzy(block)) { + return true; + } + } + + return false; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java b/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java new file mode 100644 index 0000000..6e73026 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java @@ -0,0 +1,75 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.google.common.collect.Maps; +import com.sk89q.worldedit.blocks.Blocks; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.Map; +import java.util.Objects; +import javax.annotation.Nullable; + +public class BlockStateMask extends AbstractExtentMask { + + private final Map states; + private final boolean strict; + private final Map, Object>> cache = Maps.newHashMap(); + + /** + * Creates a mask that checks if a given block has the desired properties set to the desired value. + * + * @param extent the extent to get blocks from + * @param states the desired states (property -> value) that a block should have to match the mask + * @param strict true to only match blocks that have all properties and values, false to also match blocks that + * do not have the properties (but only fail blocks with the properties but wrong values) + */ + public BlockStateMask(Extent extent, Map states, boolean strict) { + super(extent); + this.states = states; + this.strict = strict; + } + + @Override + public boolean test(BlockVector3 vector) { + BlockState block = getExtent().getBlock(vector); + final Map, Object> checkProps = cache + .computeIfAbsent(block.getBlockType(), (b -> Blocks.resolveProperties(states, b))); + if (strict && checkProps.isEmpty()) { + return false; + } + for (Map.Entry, Object> entry : checkProps.entrySet()) { + if (!Objects.equals(block.getState(entry.getKey()), entry.getValue())) { + return false; + } + } + return true; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java b/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java new file mode 100644 index 0000000..819bcc9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java @@ -0,0 +1,105 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockType; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that checks whether blocks at the given positions are matched by + * a block in a list. + * + *

This mask checks for ONLY the block type. If state should also be checked, + * use {@link BlockMask}.

+ */ +public class BlockTypeMask extends AbstractExtentMask { + + private final Set blocks = new HashSet<>(); + + /** + * Create a new block mask. + * + * @param extent the extent + * @param blocks a list of blocks to match + */ + public BlockTypeMask(Extent extent, Collection blocks) { + super(extent); + checkNotNull(blocks); + this.blocks.addAll(blocks); + } + + /** + * Create a new block mask. + * + * @param extent the extent + * @param block an array of blocks to match + */ + public BlockTypeMask(Extent extent, BlockType... block) { + this(extent, Arrays.asList(checkNotNull(block))); + } + + /** + * Add the given blocks to the list of criteria. + * + * @param blocks a list of blocks + */ + public void add(Collection blocks) { + checkNotNull(blocks); + this.blocks.addAll(blocks); + } + + /** + * Add the given blocks to the list of criteria. + * + * @param block an array of blocks + */ + public void add(BlockType... block) { + add(Arrays.asList(checkNotNull(block))); + } + + /** + * Get the list of blocks that are tested with. + * + * @return a list of blocks + */ + public Collection getBlocks() { + return blocks; + } + + @Override + public boolean test(BlockVector3 vector) { + return blocks.contains(getExtent().getBlock(vector).getBlockType()); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java b/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java new file mode 100644 index 0000000..10e969c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java @@ -0,0 +1,60 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector3; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Has the criteria where the Y value of passed positions must be within + * a certain range of Y values (inclusive). + */ +public class BoundedHeightMask extends AbstractMask { + + private final int minY; + private final int maxY; + + /** + * Create a new bounded height mask. + * + * @param minY the minimum Y + * @param maxY the maximum Y (must be equal to or greater than minY) + */ + public BoundedHeightMask(int minY, int maxY) { + checkArgument(minY <= maxY, "minY <= maxY required"); + this.minY = minY; + this.maxY = maxY; + } + + @Override + public boolean test(BlockVector3 vector) { + return vector.getY() >= minY && vector.getY() <= maxY; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java b/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java new file mode 100644 index 0000000..7619c15 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; + +import javax.annotation.Nullable; + +/** + * A mask that returns true whenever the block at the location is not + * an air block (it contains some other block). + */ +public class ExistingBlockMask extends AbstractExtentMask { + + /** + * Create a new existing block map. + * + * @param extent the extent to check + */ + public ExistingBlockMask(Extent extent) { + super(extent); + } + + @Override + public boolean test(BlockVector3 vector) { + return !getExtent().getBlock(vector).getBlockType().getMaterial().isAir(); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java b/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java new file mode 100644 index 0000000..cfffe28 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.internal.expression.EvaluationException; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; + +import java.util.function.IntSupplier; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that evaluates an expression. + * + *

Expressions are evaluated as {@code true} if they return a value + * greater than {@code 0}.

+ */ +public class ExpressionMask extends AbstractMask { + + private final Expression expression; + private final IntSupplier timeout; + + /** + * Create a new instance. + * + * @param expression the expression + * @throws ExpressionException thrown if there is an error with the expression + */ + public ExpressionMask(String expression) throws ExpressionException { + this(Expression.compile(checkNotNull(expression), "x", "y", "z")); + } + + /** + * Create a new instance. + * + * @param expression the expression + */ + public ExpressionMask(Expression expression) { + this(expression, null); + } + + public ExpressionMask(Expression expression, @Nullable IntSupplier timeout) { + checkNotNull(expression); + this.expression = expression; + this.timeout = timeout; + } + + @Override + public boolean test(BlockVector3 vector) { + try { + if (expression.getEnvironment() instanceof WorldEditExpressionEnvironment) { + ((WorldEditExpressionEnvironment) expression.getEnvironment()).setCurrentBlock(vector.toVector3()); + } + if (timeout == null) { + return expression.evaluate(vector.getX(), vector.getY(), vector.getZ()) > 0; + } else { + return expression.evaluate(new double[]{vector.getX(), vector.getY(), vector.getZ()}, + timeout.getAsInt()) > 0; + } + } catch (EvaluationException e) { + return false; + } + } + + @Nullable + @Override + public Mask2D toMask2D() { + return new ExpressionMask2D(expression, timeout); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java b/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java new file mode 100644 index 0000000..b1d9f39 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java @@ -0,0 +1,75 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.internal.expression.EvaluationException; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.math.BlockVector2; + +import java.util.function.IntSupplier; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ExpressionMask2D extends AbstractMask2D { + + private final Expression expression; + private final IntSupplier timeout; + + /** + * Create a new instance. + * + * @param expression the expression + * @throws ExpressionException thrown if there is an error with the expression + */ + public ExpressionMask2D(String expression) throws ExpressionException { + this(Expression.compile(checkNotNull(expression), "x", "z")); + } + + /** + * Create a new instance. + * + * @param expression the expression + */ + public ExpressionMask2D(Expression expression) { + this(expression, null); + } + + public ExpressionMask2D(Expression expression, @Nullable IntSupplier timeout) { + checkNotNull(expression); + this.expression = expression; + this.timeout = timeout; + } + + @Override + public boolean test(BlockVector2 vector) { + try { + if (timeout != null) { + return expression.evaluate(vector.getX(), 0, vector.getZ()) > 0; + } else { + return expression.evaluate(new double[]{vector.getX(), 0, vector.getZ()}, timeout.getAsInt()) > 0; + } + } catch (EvaluationException e) { + return false; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/src/main/java/com/sk89q/worldedit/function/mask/Mask.java new file mode 100644 index 0000000..4fc9a40 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector3; + +import javax.annotation.Nullable; + +/** + * Tests whether a given vector meets a criteria. + */ +public interface Mask { + + /** + * Returns true if the criteria is met. + * + * @param vector the vector to test + * @return true if the criteria is met + */ + boolean test(BlockVector3 vector); + + /** + * Get the 2D version of this mask if one exists. + * + * @return a 2D mask version or {@code null} if this mask can't be 2D + */ + @Nullable + Mask2D toMask2D(); + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/Mask2D.java b/src/main/java/com/sk89q/worldedit/function/mask/Mask2D.java new file mode 100644 index 0000000..efc6901 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/Mask2D.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector2; + +/** + * Tests whether a given vector meets a criteria. + */ +public interface Mask2D { + + /** + * Returns true if the criteria is met. + * + * @param vector the vector to test + * @return true if the criteria is met + */ + boolean test(BlockVector2 vector); + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java b/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java new file mode 100644 index 0000000..9d18e7b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java @@ -0,0 +1,115 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector3; + +import javax.annotation.Nullable; +import java.util.*; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Combines several masks and requires that all masks return true + * when a certain position is tested. It serves as a logical AND operation + * on a list of masks. + */ +public class MaskIntersection extends AbstractMask { + + private final Set masks = new HashSet<>(); + + /** + * Create a new intersection. + * + * @param masks a list of masks + */ + public MaskIntersection(Collection masks) { + checkNotNull(masks); + this.masks.addAll(masks); + } + + /** + * Create a new intersection. + * + * @param mask a list of masks + */ + public MaskIntersection(Mask... mask) { + this(Arrays.asList(checkNotNull(mask))); + } + + /** + * Add some masks to the list. + * + * @param masks the masks + */ + public void add(Collection masks) { + checkNotNull(masks); + this.masks.addAll(masks); + } + + /** + * Add some masks to the list. + * + * @param mask the masks + */ + public void add(Mask... mask) { + add(Arrays.asList(checkNotNull(mask))); + } + + /** + * Get the masks that are tested with. + * + * @return the masks + */ + public Collection getMasks() { + return masks; + } + + @Override + public boolean test(BlockVector3 vector) { + if (masks.isEmpty()) { + return false; + } + + for (Mask mask : masks) { + if (!mask.test(vector)) { + return false; + } + } + + return true; + } + + @Nullable + @Override + public Mask2D toMask2D() { + List mask2dList = new ArrayList<>(); + for (Mask mask : masks) { + Mask2D mask2d = mask.toMask2D(); + if (mask2d != null) { + mask2dList.add(mask2d); + } else { + return null; + } + } + return new MaskIntersection2D(mask2dList); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection2D.java b/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection2D.java new file mode 100644 index 0000000..12ab2b0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection2D.java @@ -0,0 +1,100 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector2; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Tests true if all contained masks test true. + */ +public class MaskIntersection2D implements Mask2D { + + private final Set masks = new HashSet<>(); + + /** + * Create a new intersection. + * + * @param masks a list of masks + */ + public MaskIntersection2D(Collection masks) { + checkNotNull(masks); + this.masks.addAll(masks); + } + + /** + * Create a new intersection. + * + * @param mask a list of masks + */ + public MaskIntersection2D(Mask2D... mask) { + this(Arrays.asList(checkNotNull(mask))); + } + + /** + * Add some masks to the list. + * + * @param masks the masks + */ + public void add(Collection masks) { + checkNotNull(masks); + this.masks.addAll(masks); + } + + /** + * Add some masks to the list. + * + * @param mask the masks + */ + public void add(Mask2D... mask) { + add(Arrays.asList(checkNotNull(mask))); + } + + /** + * Get the masks that are tested with. + * + * @return the masks + */ + public Collection getMasks() { + return masks; + } + + @Override + public boolean test(BlockVector2 vector) { + if (masks.isEmpty()) { + return false; + } + + for (Mask2D mask : masks) { + if (!mask.test(vector)) { + return false; + } + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java b/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java new file mode 100644 index 0000000..97e274c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector3; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.annotation.Nullable; + +/** + * Combines several masks and requires that one or more masks return true + * when a certain position is tested. It serves as a logical OR operation + * on a list of masks. + */ +public class MaskUnion extends MaskIntersection { + + /** + * Create a new union. + * + * @param masks a list of masks + */ + public MaskUnion(Collection masks) { + super(masks); + } + + /** + * Create a new union. + * + * @param mask a list of masks + */ + public MaskUnion(Mask... mask) { + super(mask); + } + + @Override + public boolean test(BlockVector3 vector) { + Collection masks = getMasks(); + + for (Mask mask : masks) { + if (mask.test(vector)) { + return true; + } + } + + return false; + } + + @Nullable + @Override + public Mask2D toMask2D() { + List mask2dList = new ArrayList<>(); + for (Mask mask : getMasks()) { + Mask2D mask2d = mask.toMask2D(); + if (mask2d != null) { + mask2dList.add(mask2d); + } else { + return null; + } + } + return new MaskUnion2D(mask2dList); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java b/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java new file mode 100644 index 0000000..daf1a6e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector2; + +import java.util.Collection; + +/** + * Tests true if any contained mask is true, even if it just one. + */ +public class MaskUnion2D extends MaskIntersection2D { + + /** + * Create a new union. + * + * @param masks a list of masks + */ + public MaskUnion2D(Collection masks) { + super(masks); + } + + /** + * Create a new union. + * + * @param mask a list of masks + */ + public MaskUnion2D(Mask2D... mask) { + super(mask); + } + + @Override + public boolean test(BlockVector2 vector) { + Collection masks = getMasks(); + + for (Mask2D mask : masks) { + if (mask.test(vector)) { + return true; + } + } + + return false; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/Masks.java b/src/main/java/com/sk89q/worldedit/function/mask/Masks.java new file mode 100644 index 0000000..5205e7d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/Masks.java @@ -0,0 +1,188 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Various utility functions related to {@link Mask} and {@link Mask2D}. + */ +public final class Masks { + + private static final AlwaysTrue ALWAYS_TRUE = new AlwaysTrue(); + private static final AlwaysFalse ALWAYS_FALSE = new AlwaysFalse(); + + private Masks() { + } + + /** + * Return a 3D mask that always returns true. + * + * @return a mask + */ + public static Mask alwaysTrue() { + return ALWAYS_TRUE; + } + + /** + * Return a 2D mask that always returns true. + * + * @return a mask + */ + public static Mask2D alwaysTrue2D() { + return ALWAYS_TRUE; + } + + /** + * Negate the given mask. + * + * @param mask the mask + * @return a new mask + */ + public static Mask negate(final Mask mask) { + if (mask instanceof AlwaysTrue) { + return ALWAYS_FALSE; + } else if (mask instanceof AlwaysFalse) { + return ALWAYS_TRUE; + } else if (mask instanceof NegatedMask) { + return ((NegatedMask) mask).mask; + } + + checkNotNull(mask); + return new NegatedMask(mask); + } + + /** + * Negate the given mask. + * + * @param mask the mask + * @return a new mask + */ + public static Mask2D negate(final Mask2D mask) { + if (mask instanceof AlwaysTrue) { + return ALWAYS_FALSE; + } else if (mask instanceof AlwaysFalse) { + return ALWAYS_TRUE; + } else if (mask instanceof NegatedMask2D) { + return ((NegatedMask2D) mask).mask; + } + + checkNotNull(mask); + return new NegatedMask2D(mask); + } + + /** + * Return a 3-dimensional version of a 2D mask. + * + * @param mask the mask to make 3D + * @return a 3D mask + */ + public static Mask asMask(final Mask2D mask) { + return new AbstractMask() { + @Override + public boolean test(BlockVector3 vector) { + return mask.test(vector.toBlockVector2()); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return mask; + } + }; + } + + private static class AlwaysTrue implements Mask, Mask2D { + @Override + public boolean test(BlockVector3 vector) { + return true; + } + + @Override + public boolean test(BlockVector2 vector) { + return true; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return this; + } + } + + private static class AlwaysFalse implements Mask, Mask2D { + @Override + public boolean test(BlockVector3 vector) { + return false; + } + + @Override + public boolean test(BlockVector2 vector) { + return false; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return this; + } + } + + private static class NegatedMask implements Mask { + private final Mask mask; + + private NegatedMask(Mask mask) { + this.mask = mask; + } + + @Override + public boolean test(BlockVector3 vector) { + return !mask.test(vector); + } + + @Nullable + @Override + public Mask2D toMask2D() { + Mask2D mask2D = mask.toMask2D(); + if (mask2D == null) { + return null; + } + return negate(mask2D); + } + } + + private static class NegatedMask2D implements Mask2D { + private final Mask2D mask; + + private NegatedMask2D(Mask2D mask) { + this.mask = mask; + } + + @Override + public boolean test(BlockVector2 vector) { + return !mask.test(vector); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java b/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java new file mode 100644 index 0000000..5c0089f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java @@ -0,0 +1,98 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.noise.NoiseGenerator; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that uses a noise generator and returns true whenever the noise + * generator returns a value above the given density. + */ +public class NoiseFilter extends AbstractMask { + + private NoiseGenerator noiseGenerator; + private double density; + + /** + * Create a new noise filter. + * + * @param noiseGenerator the noise generator + * @param density the density + */ + public NoiseFilter(NoiseGenerator noiseGenerator, double density) { + setNoiseGenerator(noiseGenerator); + setDensity(density); + } + + /** + * Get the noise generator. + * + * @return the noise generator + */ + public NoiseGenerator getNoiseGenerator() { + return noiseGenerator; + } + + /** + * Set the noise generator. + * + * @param noiseGenerator a noise generator + */ + public void setNoiseGenerator(NoiseGenerator noiseGenerator) { + checkNotNull(noiseGenerator); + this.noiseGenerator = noiseGenerator; + } + + /** + * Get the probability of passing as a number between 0 and 1 (inclusive). + * + * @return the density + */ + public double getDensity() { + return density; + } + + /** + * Set the probability of passing as a number between 0 and 1 (inclusive). + */ + public void setDensity(double density) { + checkArgument(density >= 0, "density must be >= 0"); + checkArgument(density <= 1, "density must be <= 1"); + this.density = density; + } + + @Override + public boolean test(BlockVector3 vector) { + return noiseGenerator.noise(vector.toVector3()) <= density; + } + + @Nullable + @Override + public Mask2D toMask2D() { + return new NoiseFilter2D(getNoiseGenerator(), getDensity()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java b/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java new file mode 100644 index 0000000..ac59d3e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java @@ -0,0 +1,90 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.noise.NoiseGenerator; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that uses a noise generator and returns true whenever the noise + * generator returns a value above the given density. + */ +public class NoiseFilter2D extends AbstractMask2D { + + private NoiseGenerator noiseGenerator; + private double density; + + /** + * Create a new noise filter. + * + * @param noiseGenerator the noise generator + * @param density the density + */ + public NoiseFilter2D(NoiseGenerator noiseGenerator, double density) { + setNoiseGenerator(noiseGenerator); + setDensity(density); + } + + /** + * Get the noise generator. + * + * @return the noise generator + */ + public NoiseGenerator getNoiseGenerator() { + return noiseGenerator; + } + + /** + * Set the noise generator. + * + * @param noiseGenerator a noise generator + */ + public void setNoiseGenerator(NoiseGenerator noiseGenerator) { + checkNotNull(noiseGenerator); + this.noiseGenerator = noiseGenerator; + } + + /** + * Get the probability of passing as a number between 0 and 1 (inclusive). + * + * @return the density + */ + public double getDensity() { + return density; + } + + /** + * Set the probability of passing as a number between 0 and 1 (inclusive). + */ + public void setDensity(double density) { + checkArgument(density >= 0, "density must be >= 0"); + checkArgument(density <= 1, "density must be <= 1"); + this.density = density; + } + + @Override + public boolean test(BlockVector2 pos) { + return noiseGenerator.noise(pos.toVector2()) <= density; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java b/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java new file mode 100644 index 0000000..3a4544c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java @@ -0,0 +1,107 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector3; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Checks whether another mask tests true for a position that is offset + * a given vector. + * + * @deprecated Use {@link OffsetsMask#single} + */ +@Deprecated +public class OffsetMask extends AbstractMask { + + private Mask mask; + private BlockVector3 offset; + + /** + * Create a new instance. + * + * @param mask the mask + * @param offset the offset + */ + public OffsetMask(Mask mask, BlockVector3 offset) { + checkNotNull(mask); + checkNotNull(offset); + this.mask = mask; + this.offset = offset; + } + + /** + * Get the mask. + * + * @return the mask + */ + public Mask getMask() { + return mask; + } + + /** + * Set the mask. + * + * @param mask the mask + */ + public void setMask(Mask mask) { + checkNotNull(mask); + this.mask = mask; + } + + /** + * Get the offset. + * + * @return the offset + */ + public BlockVector3 getOffset() { + return offset; + } + + /** + * Set the offset. + * + * @param offset the offset + */ + public void setOffset(BlockVector3 offset) { + checkNotNull(offset); + this.offset = offset; + } + + @Override + public boolean test(BlockVector3 vector) { + return getMask().test(vector.add(offset)); + } + + @Nullable + @Override + public Mask2D toMask2D() { + Mask2D childMask = getMask().toMask2D(); + if (childMask != null) { + return OffsetsMask2D.single(childMask, getOffset().toBlockVector2()); + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java b/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java new file mode 100644 index 0000000..7eb87b5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java @@ -0,0 +1,94 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector2; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Checks whether another mask tests true for a position that is offset + * a given vector. + * + * @deprecated Use {@link OffsetsMask2D#single} + */ +@Deprecated +public class OffsetMask2D extends AbstractMask2D { + + private Mask2D mask; + private BlockVector2 offset; + + /** + * Create a new instance. + * + * @param mask the mask + * @param offset the offset + */ + public OffsetMask2D(Mask2D mask, BlockVector2 offset) { + checkNotNull(mask); + checkNotNull(offset); + this.mask = mask; + this.offset = offset; + } + + /** + * Get the mask. + * + * @return the mask + */ + public Mask2D getMask() { + return mask; + } + + /** + * Set the mask. + * + * @param mask the mask + */ + public void setMask(Mask2D mask) { + checkNotNull(mask); + this.mask = mask; + } + + /** + * Get the offset. + * + * @return the offset + */ + public BlockVector2 getOffset() { + return offset; + } + + /** + * Set the offset. + * + * @param offset the offset + */ + public void setOffset(BlockVector2 offset) { + checkNotNull(offset); + this.offset = offset; + } + + @Override + public boolean test(BlockVector2 vector) { + return getMask().test(vector.add(offset)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/OffsetsMask.java b/src/main/java/com/sk89q/worldedit/function/mask/OffsetsMask.java new file mode 100644 index 0000000..77140b1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/OffsetsMask.java @@ -0,0 +1,249 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Direction.Flag; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Checks whether any face of the given offsets to a block match a given mask. + */ +public class OffsetsMask extends AbstractMask { + + private static final ImmutableSet OFFSET_LIST = + Direction.valuesOf(Flag.CARDINAL | Flag.UPRIGHT) + .stream() + .map(Direction::toBlockVector) + .collect(ImmutableSet.toImmutableSet()); + + /** + * Create an offsets mask for a single offset. + * + * @param mask the mask to use + * @param offset the offset + * @return the new offsets mask + */ + public static OffsetsMask single(Mask mask, BlockVector3 offset) { + return builder(mask).maxMatches(1).offsets(ImmutableList.of(offset)).build(); + } + + /** + * Create a new builder, using the given mask. + * @param mask the mask to use + * @return the builder + */ + public static Builder builder(Mask mask) { + return new Builder().mask(mask); + } + + /** + * A builder for an {@link OffsetsMask}. + */ + public static final class Builder { + private Mask mask; + private boolean excludeSelf; + private int minMatches = 1; + private int maxMatches = Integer.MAX_VALUE; + private ImmutableSet offsets = OFFSET_LIST; + + private Builder() { + } + + /** + * Set the mask to test. + * @param mask the mask to test + * @return this builder, for chaining + */ + public Builder mask(Mask mask) { + this.mask = mask; + return this; + } + + /** + * Set whether the mask should fail if the original position matches. Defaults to + * {@code false}. + * + * @param excludeSelf {@code true} to exclude the original position if it matches + * @return this builder, for chaining + */ + public Builder excludeSelf(boolean excludeSelf) { + this.excludeSelf = excludeSelf; + return this; + } + + /** + * Set the minimum amount of matches required. Defaults to {@code 1}. Must be smaller than + * or equal to the {@linkplain #maxMatches(int) max matches} and the {@link #offsets} size, + * and greater than or equal to {@code 0}. + * + * @param minMatches the minimum amount of matches required + * @return this builder, for chaining + */ + public Builder minMatches(int minMatches) { + this.minMatches = minMatches; + return this; + } + + /** + * Set the maximum amount of matches allowed. Defaults to {@link Integer#MAX_VALUE}. Must + * be greater than or equal to {@linkplain #minMatches(int)}. + * + * @param maxMatches the maximum amount of matches allowed + * @return this builder, for chaining + */ + public Builder maxMatches(int maxMatches) { + this.maxMatches = maxMatches; + return this; + } + + /** + * Set the offsets to test. Defaults to all {@linkplain Flag#CARDINAL cardinal} + * and {@linkplain Flag#UPRIGHT upright} directions. + * + * @param offsets the offsets to test + * @return this builder, for chaining + */ + public Builder offsets(Iterable offsets) { + this.offsets = ImmutableSet.copyOf(offsets); + return this; + } + + /** + * Build an offsets mask. + * + * @return the new mask + */ + public OffsetsMask build() { + return new OffsetsMask(mask, excludeSelf, minMatches, maxMatches, offsets); + } + } + + private final Mask mask; + private final boolean excludeSelf; + private final int minMatches; + private final int maxMatches; + private final ImmutableSet offsets; + + private OffsetsMask(Mask mask, boolean excludeSelf, int minMatches, int maxMatches, ImmutableSet offsets) { + checkNotNull(mask); + checkNotNull(offsets); + // Validate match args. No need to test maxMatches as it must be >=0 based on the conditions here. + checkArgument(minMatches <= maxMatches, "minMatches must be less than or equal to maxMatches"); + checkArgument(minMatches >= 0, "minMatches must be greater than or equal to 0"); + checkArgument(minMatches <= offsets.size(), "minMatches must be less than or equal to the number of offsets"); + checkArgument(offsets.size() > 0, "offsets must have at least one element"); + + this.mask = mask; + this.excludeSelf = excludeSelf; + this.minMatches = minMatches; + this.maxMatches = maxMatches; + this.offsets = offsets; + } + + /** + * Get the mask. + * + * @return the mask + */ + public Mask getMask() { + return mask; + } + + /** + * Get the flag determining if matching the current block should fail the mask. + * + * @return if it should exclude self-matches + */ + public boolean getExcludeSelf() { + return this.excludeSelf; + } + + /** + * Gets the minimum number of matches to pass. + * + * @return the minimum number of matches + */ + public int getMinMatches() { + return this.minMatches; + } + + /** + * Gets the maximum number of matches to pass. + * + * @return the maximum number of matches + */ + public int getMaxMatches() { + return this.maxMatches; + } + + /** + * Get the offsets. + * + * @return the offsets + */ + public ImmutableSet getOffsets() { + return this.offsets; + } + + @Override + public boolean test(BlockVector3 vector) { + if (excludeSelf && mask.test(vector)) { + return false; + } + + int matches = 0; + + for (BlockVector3 offset : offsets) { + if (mask.test(vector.add(offset))) { + matches++; + if (matches > maxMatches) { + return false; + } + } + } + + return minMatches <= matches && matches <= maxMatches; + } + + @Nullable + @Override + public Mask2D toMask2D() { + Mask2D childMask = getMask().toMask2D(); + if (childMask != null) { + return OffsetsMask2D.builder(childMask) + .excludeSelf(excludeSelf) + .minMatches(minMatches) + .maxMatches(maxMatches) + .offsets(Iterables.transform(offsets, BlockVector3::toBlockVector2)) + .build(); + } else { + return null; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/OffsetsMask2D.java b/src/main/java/com/sk89q/worldedit/function/mask/OffsetsMask2D.java new file mode 100644 index 0000000..7dfb603 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/OffsetsMask2D.java @@ -0,0 +1,232 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Direction.Flag; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Checks whether any face of the given offsets to a block match a given mask. + */ +public class OffsetsMask2D extends AbstractMask2D { + + private static final ImmutableSet OFFSET_LIST = + Direction.valuesOf(Flag.CARDINAL) + .stream() + .map(Direction::toBlockVector) + .map(BlockVector3::toBlockVector2) + .collect(ImmutableSet.toImmutableSet()); + + /** + * Create an offsets mask for a single offset. + * + * @param mask the mask to use + * @param offset the offset + * @return the new offsets mask + */ + public static OffsetsMask2D single(Mask2D mask, BlockVector2 offset) { + return builder(mask).maxMatches(1).offsets(ImmutableList.of(offset)).build(); + } + + /** + * Create a new builder, using the given mask. + * @param mask the mask to use + * @return the builder + */ + public static Builder builder(Mask2D mask) { + return new Builder().mask(mask); + } + + /** + * A builder for an {@link OffsetsMask}. + */ + public static final class Builder { + private Mask2D mask; + private boolean excludeSelf; + private int minMatches = 1; + private int maxMatches = Integer.MAX_VALUE; + private ImmutableSet offsets = OFFSET_LIST; + + private Builder() { + } + + /** + * Set the mask to test. + * @param mask the mask to test + * @return this builder, for chaining + */ + public Builder mask(Mask2D mask) { + this.mask = mask; + return this; + } + + /** + * Set whether the mask should fail if the original position matches. Defaults to + * {@code false}. + * + * @param excludeSelf {@code true} to exclude the original position if it matches + * @return this builder, for chaining + */ + public Builder excludeSelf(boolean excludeSelf) { + this.excludeSelf = excludeSelf; + return this; + } + + /** + * Set the minimum amount of matches required. Defaults to {@code 1}. Must be smaller than + * or equal to the {@linkplain #maxMatches(int) max matches} and the {@link #offsets} size, + * and greater than or equal to {@code 0}. + * + * @param minMatches the minimum amount of matches required + * @return this builder, for chaining + */ + public Builder minMatches(int minMatches) { + this.minMatches = minMatches; + return this; + } + + /** + * Set the maximum amount of matches allowed. Defaults to {@link Integer#MAX_VALUE}. Must + * be greater than or equal to {@linkplain #minMatches(int)}. + * + * @param maxMatches the maximum amount of matches allowed + * @return this builder, for chaining + */ + public Builder maxMatches(int maxMatches) { + this.maxMatches = maxMatches; + return this; + } + + /** + * Set the offsets to test. Defaults to all {@linkplain Flag#CARDINAL cardinal} + * directions. + * + * @param offsets the offsets to test + * @return this builder, for chaining + */ + public Builder offsets(Iterable offsets) { + this.offsets = ImmutableSet.copyOf(offsets); + return this; + } + + /** + * Build an offsets mask. + * + * @return the new mask + */ + public OffsetsMask2D build() { + return new OffsetsMask2D(mask, excludeSelf, minMatches, maxMatches, offsets); + } + } + + private final Mask2D mask; + private final boolean excludeSelf; + private final int minMatches; + private final int maxMatches; + private final ImmutableSet offsets; + + private OffsetsMask2D(Mask2D mask, boolean excludeSelf, int minMatches, int maxMatches, ImmutableSet offsets) { + checkNotNull(mask); + checkNotNull(offsets); + // Validate match args. No need to test maxMatches as it must be >=0 based on the conditions here. + checkArgument(minMatches <= maxMatches, "minMatches must be less than or equal to maxMatches"); + checkArgument(minMatches >= 0, "minMatches must be greater than or equal to 0"); + checkArgument(minMatches <= offsets.size(), "minMatches must be less than or equal to the number of offsets"); + checkArgument(offsets.size() > 0, "offsets must have at least one element"); + + this.mask = mask; + this.excludeSelf = excludeSelf; + this.minMatches = minMatches; + this.maxMatches = maxMatches; + this.offsets = offsets; + } + + /** + * Get the mask. + * + * @return the mask + */ + public Mask2D getMask() { + return mask; + } + + /** + * Get the flag determining if matching the current block should fail the mask. + * + * @return if it should exclude self-matches + */ + public boolean getExcludeSelf() { + return this.excludeSelf; + } + + /** + * Gets the minimum number of matches to pass. + * + * @return the minimum number of matches + */ + public int getMinMatches() { + return this.minMatches; + } + + /** + * Gets the maximum number of matches to pass. + * + * @return the maximum number of matches + */ + public int getMaxMatches() { + return this.maxMatches; + } + + /** + * Get the offsets. + * + * @return the offsets + */ + public ImmutableSet getOffsets() { + return this.offsets; + } + + @Override + public boolean test(BlockVector2 vector) { + if (excludeSelf && mask.test(vector)) { + return false; + } + + int matches = 0; + + for (BlockVector2 offset : offsets) { + if (mask.test(vector.add(offset))) { + matches++; + if (matches > maxMatches) { + return false; + } + } + } + + return minMatches <= matches && matches <= maxMatches; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java b/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java new file mode 100644 index 0000000..a3f0032 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java @@ -0,0 +1,75 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that tests whether given positions are contained within a region. + */ +public class RegionMask extends AbstractMask { + + private Region region; + + /** + * Create a new region mask. + * + * @param region the region + */ + public RegionMask(Region region) { + setRegion(region); + } + + /** + * Get the region. + * + * @return the region + */ + public Region getRegion() { + return region; + } + + /** + * Set the region that positions must be contained within. + * + * @param region the region + */ + public void setRegion(Region region) { + checkNotNull(region); + this.region = region; + } + + @Override + public boolean test(BlockVector3 vector) { + return region.contains(vector); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java b/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java new file mode 100644 index 0000000..158d653 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; + +import javax.annotation.Nullable; + +public class SolidBlockMask extends AbstractExtentMask { + + public SolidBlockMask(Extent extent) { + super(extent); + } + + @Override + public boolean test(BlockVector3 vector) { + Extent extent = getExtent(); + BlockState block = extent.getBlock(vector); + return block.getBlockType().getMaterial().isMovementBlocker(); + } + + @Nullable + @Override + public Mask2D toMask2D() { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java b/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java new file mode 100644 index 0000000..6cf9e5e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java @@ -0,0 +1,104 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.operation; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.history.change.Change; +import com.sk89q.worldedit.history.changeset.ChangeSet; + +import java.util.Iterator; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Performs an undo or redo from a given {@link ChangeSet}. + */ +public class ChangeSetExecutor implements Operation { + + public enum Type { UNDO, REDO } + + private final Iterator iterator; + private final Type type; + private final UndoContext context; + + /** + * Create a new instance. + * + * @param changeSet the change set + * @param type type of change + * @param context the undo context + */ + private ChangeSetExecutor(ChangeSet changeSet, Type type, UndoContext context) { + checkNotNull(changeSet); + checkNotNull(type); + checkNotNull(context); + + this.type = type; + this.context = context; + + if (type == Type.UNDO) { + iterator = changeSet.backwardIterator(); + } else { + iterator = changeSet.forwardIterator(); + } + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + while (iterator.hasNext()) { + Change change = iterator.next(); + if (type == Type.UNDO) { + change.undo(context); + } else { + change.redo(context); + } + } + + return null; + } + + @Override + public void cancel() { + } + + /** + * Create a new undo operation. + * + * @param changeSet the change set + * @param context an undo context + * @return an operation + */ + public static ChangeSetExecutor createUndo(ChangeSet changeSet, UndoContext context) { + return new ChangeSetExecutor(changeSet, Type.UNDO, context); + } + + /** + * Create a new redo operation. + * + * @param changeSet the change set + * @param context an undo context + * @return an operation + */ + public static ChangeSetExecutor createRedo(ChangeSet changeSet, UndoContext context) { + return new ChangeSetExecutor(changeSet, Type.REDO, context); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/DelegateOperation.java b/src/main/java/com/sk89q/worldedit/function/operation/DelegateOperation.java new file mode 100644 index 0000000..a9d76ff --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/DelegateOperation.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.operation; + +import com.google.common.collect.Iterables; +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.Component; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Executes a delegate operation, but returns to another operation upon + * completing the delegate. + */ +public class DelegateOperation implements Operation { + + private final Operation original; + private Operation delegate; + + /** + * Create a new operation delegate. + * + * @param original the operation to return to + * @param delegate the delegate operation to complete before returning + */ + public DelegateOperation(Operation original, Operation delegate) { + checkNotNull(original); + checkNotNull(delegate); + this.original = original; + this.delegate = delegate; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + delegate = delegate.resume(run); + return delegate != null ? this : original; + } + + @Override + public void cancel() { + delegate.cancel(); + original.cancel(); + } + + @Override + public Iterable getStatusMessages() { + return Iterables.concat(original.getStatusMessages(), delegate.getStatusMessages()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java b/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java new file mode 100644 index 0000000..785ab8b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java @@ -0,0 +1,347 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.operation; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.metadata.EntityProperties; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.CombinedRegionFunction; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.RegionMaskingFilter; +import com.sk89q.worldedit.function.biome.ExtentBiomeCopy; +import com.sk89q.worldedit.function.block.ExtentBlockCopy; +import com.sk89q.worldedit.function.entity.ExtentEntityCopy; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.visitor.EntityVisitor; +import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.transform.Identity; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.Region; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Makes a copy of a portion of one extent to another extent or another point. + * + *

This is a forward extent copy, meaning that it iterates over the blocks + * in the source extent, and will copy as many blocks as there are in the + * source. Therefore, interpolation will not occur to fill in the gaps.

+ */ +public class ForwardExtentCopy implements Operation { + + private final Extent source; + private final Extent destination; + private final Region region; + private final BlockVector3 from; + private final BlockVector3 to; + private int repetitions = 1; + private Mask sourceMask = Masks.alwaysTrue(); + private boolean removingEntities; + private boolean copyingEntities = true; // default to true for backwards compatibility, sort of + private boolean copyingBiomes; + private RegionFunction sourceFunction = null; + private Transform transform = new Identity(); + private Transform currentTransform = null; + + private RegionVisitor lastVisitor; + private RegionVisitor lastBiomeVisitor; + private EntityVisitor lastEntityVisitor; + + private int affectedBlocks; + private int affectedBiomeCols; + private int affectedEntities; + + /** + * Create a new copy using the region's lowest minimum point as the + * "from" position. + * + * @param source the source extent + * @param region the region to copy + * @param destination the destination extent + * @param to the destination position + * @see #ForwardExtentCopy(Extent, Region, BlockVector3, Extent, BlockVector3) the main constructor + */ + public ForwardExtentCopy(Extent source, Region region, Extent destination, BlockVector3 to) { + this(source, region, region.getMinimumPoint(), destination, to); + } + + /** + * Create a new copy. + * + * @param source the source extent + * @param region the region to copy + * @param from the source position + * @param destination the destination extent + * @param to the destination position + */ + public ForwardExtentCopy(Extent source, Region region, BlockVector3 from, Extent destination, BlockVector3 to) { + checkNotNull(source); + checkNotNull(region); + checkNotNull(from); + checkNotNull(destination); + checkNotNull(to); + this.source = source; + this.destination = destination; + this.region = region; + this.from = from; + this.to = to; + } + + /** + * Get the transformation that will occur on every point. + * + *

The transformation will stack with each repetition.

+ * + * @return a transformation + */ + public Transform getTransform() { + return transform; + } + + /** + * Set the transformation that will occur on every point. + * + * @param transform a transformation + * @see #getTransform() + */ + public void setTransform(Transform transform) { + checkNotNull(transform); + this.transform = transform; + } + + /** + * Get the mask that gets applied to the source extent. + * + *

This mask can be used to filter what will be copied from the source.

+ * + * @return a source mask + */ + public Mask getSourceMask() { + return sourceMask; + } + + /** + * Set a mask that gets applied to the source extent. + * + * @param sourceMask a source mask + * @see #getSourceMask() + */ + public void setSourceMask(Mask sourceMask) { + checkNotNull(sourceMask); + this.sourceMask = sourceMask; + } + + /** + * Get the function that gets applied to all source blocks after + * the copy has been made. + * + * @return a source function, or null if none is to be applied + */ + public RegionFunction getSourceFunction() { + return sourceFunction; + } + + /** + * Set the function that gets applied to all source blocks after + * the copy has been made. + * + * @param function a source function, or null if none is to be applied + */ + public void setSourceFunction(RegionFunction function) { + this.sourceFunction = function; + } + + /** + * Get the number of repetitions left. + * + * @return the number of repetitions + */ + public int getRepetitions() { + return repetitions; + } + + /** + * Set the number of repetitions left. + * + * @param repetitions the number of repetitions + */ + public void setRepetitions(int repetitions) { + checkArgument(repetitions >= 0, "number of repetitions must be non-negative"); + this.repetitions = repetitions; + } + + /** + * Return whether entities should be copied along with blocks. + * + * @return true if copying + */ + public boolean isCopyingEntities() { + return copyingEntities; + } + + /** + * Set whether entities should be copied along with blocks. + * + * @param copyingEntities true if copying + */ + public void setCopyingEntities(boolean copyingEntities) { + this.copyingEntities = copyingEntities; + } + + /** + * Return whether entities that are copied should be removed. + * + * @return true if removing + */ + public boolean isRemovingEntities() { + return removingEntities; + } + + /** + * Set whether entities that are copied should be removed. + * + * @param removingEntities true if removing + */ + public void setRemovingEntities(boolean removingEntities) { + this.removingEntities = removingEntities; + } + + /** + * Return whether biomes should be copied along with blocks. + * + * @return true if copying biomes + */ + public boolean isCopyingBiomes() { + return copyingBiomes; + } + + /** + * Set whether biomes should be copies along with blocks. + * + * @param copyingBiomes true if copying + */ + public void setCopyingBiomes(boolean copyingBiomes) { + this.copyingBiomes = copyingBiomes; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affectedBlocks + affectedBiomeCols + affectedEntities; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + if (lastVisitor != null) { + affectedBlocks += lastVisitor.getAffected(); + lastVisitor = null; + } + if (lastBiomeVisitor != null) { + affectedBiomeCols += lastBiomeVisitor.getAffected(); + lastBiomeVisitor = null; + } + if (lastEntityVisitor != null) { + affectedEntities += lastEntityVisitor.getAffected(); + lastEntityVisitor = null; + } + + if (repetitions > 0) { + repetitions--; + + if (currentTransform == null) { + currentTransform = transform; + } else { + currentTransform = currentTransform.combine(transform); + } + + ExtentBlockCopy blockCopy = new ExtentBlockCopy(source, from, destination, to, currentTransform); + RegionMaskingFilter filteredFunction = new RegionMaskingFilter(sourceMask, + sourceFunction == null ? blockCopy : new CombinedRegionFunction(blockCopy, sourceFunction)); + RegionVisitor blockVisitor = new RegionVisitor(region, filteredFunction); + + lastVisitor = blockVisitor; + + if (!copyingBiomes && !copyingEntities) { + return new DelegateOperation(this, blockVisitor); + } + + List ops = Lists.newArrayList(blockVisitor); + + if (copyingBiomes) { + ExtentBiomeCopy biomeCopy = new ExtentBiomeCopy(source, from, + destination, to, currentTransform); + RegionFunction biomeFunction = sourceFunction == null ? biomeCopy + : new RegionMaskingFilter(sourceMask, biomeCopy); + RegionVisitor biomeVisitor = new RegionVisitor(region, biomeFunction); + ops.add(biomeVisitor); + lastBiomeVisitor = biomeVisitor; + } + + if (copyingEntities) { + ExtentEntityCopy entityCopy = new ExtentEntityCopy(from.toVector3(), destination, to.toVector3(), currentTransform); + entityCopy.setRemoving(removingEntities); + List entities = Lists.newArrayList(source.getEntities(region)); + entities.removeIf(entity -> { + EntityProperties properties = entity.getFacet(EntityProperties.class); + return properties != null && !properties.isPasteable(); + }); + EntityVisitor entityVisitor = new EntityVisitor(entities.iterator(), entityCopy); + ops.add(entityVisitor); + lastEntityVisitor = entityVisitor; + } + + return new DelegateOperation(this, new OperationQueue(ops)); + } else { + return null; + } + } + + @Override + public void cancel() { + } + + @Override + public Iterable getStatusMessages() { + return ImmutableList.of( + TranslatableComponent.of("worldedit.operation.affected.block", + TextComponent.of(affectedBlocks)).color(TextColor.LIGHT_PURPLE), + TranslatableComponent.of("worldedit.operation.affected.biome", + TextComponent.of(affectedBiomeCols)).color(TextColor.LIGHT_PURPLE), + TranslatableComponent.of("worldedit.operation.affected.entity", + TextComponent.of(affectedEntities)).color(TextColor.LIGHT_PURPLE) + ); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/Operation.java b/src/main/java/com/sk89q/worldedit/function/operation/Operation.java new file mode 100644 index 0000000..257b547 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/Operation.java @@ -0,0 +1,96 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.operation; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * An task that may be split into multiple steps to be run sequentially + * immediately or at a varying or fixed interval. Operations should attempt + * to break apart tasks into smaller tasks that can be completed in quicker + * successions. + */ +public interface Operation { + + /** + * Complete the next step. If this method returns true, then the method may + * be called again in the future, or possibly never. If this method + * returns false, then this method should not be called again. + * + * @param run describes information about the current run + * @return another operation to run that operation again, or null to stop + * @throws WorldEditException an error + */ + Operation resume(RunContext run) throws WorldEditException; + + /** + * Abort the current task. After the this method is called, + * {@link #resume(RunContext)} should not be called at any point in the + * future. This method should not be called after successful completion of + * the operation. This method must be called if the operation is + * interrupted before completion. + */ + void cancel(); + + /** + * Add messages to the provided list that describe the current status + * of the operation. + * + * @param messages The list to add messages to + * @deprecated Will be removed in WorldEdit 8.0 - use the Component variant + */ + @Deprecated + default void addStatusMessages(List messages) { + } + + /** + * This is an internal field, and should not be touched. + */ + Set warnedDeprecatedClasses = new HashSet<>(); + + /** + * Gets an iterable of messages that describe the current status of the + * operation. + * + * @return The status messages + */ + default Iterable getStatusMessages() { + // TODO Remove legacy code WorldEdit 8.0.0 + List oldMessages = new ArrayList<>(); + addStatusMessages(oldMessages); + if (oldMessages.size() > 0) { + String className = getClass().getName(); + if (!warnedDeprecatedClasses.contains(className)) { + WorldEdit.logger.warn("An operation is using the old status message API. This will be removed in WorldEdit 8. Class: " + className); + warnedDeprecatedClasses.add(className); + } + } + return oldMessages.stream().map(TextComponent::of).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/OperationQueue.java b/src/main/java/com/sk89q/worldedit/function/operation/OperationQueue.java new file mode 100644 index 0000000..9d75864 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/OperationQueue.java @@ -0,0 +1,115 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.operation; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.Component; + +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Deque; +import java.util.List; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Executes multiple queues in order. + */ +public class OperationQueue implements Operation { + + private final List operations = Lists.newArrayList(); + private final Deque queue = new ArrayDeque<>(); + private Operation current; + + /** + * Create a new queue containing no operations. + */ + public OperationQueue() { + } + + /** + * Create a new queue with operations from the given collection. + * + * @param operations a collection of operations + */ + public OperationQueue(Collection operations) { + checkNotNull(operations); + for (Operation operation : operations) { + offer(operation); + } + this.operations.addAll(operations); + } + + /** + * Create a new queue with operations from the given array. + * + * @param operation an array of operations + */ + public OperationQueue(Operation... operation) { + checkNotNull(operation); + for (Operation o : operation) { + offer(o); + } + } + + /** + * Add a new operation to the queue. + * + * @param operation the operation + */ + public void offer(Operation operation) { + checkNotNull(operation); + queue.offer(operation); + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + if (current == null && !queue.isEmpty()) { + current = queue.poll(); + } + + if (current != null) { + current = current.resume(run); + + if (current == null) { + current = queue.poll(); + } + } + + return current != null ? this : null; + } + + @Override + public void cancel() { + for (Operation operation : queue) { + operation.cancel(); + } + queue.clear(); + } + + @Override + public Iterable getStatusMessages() { + return Iterables.concat(operations.stream().map(Operation::getStatusMessages).collect(Collectors.toList())); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/Operations.java b/src/main/java/com/sk89q/worldedit/function/operation/Operations.java new file mode 100644 index 0000000..5f54e04 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/Operations.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.operation; + +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; + +/** + * Operation helper methods. + */ +public final class Operations { + + private Operations() { + } + + /** + * Complete a given operation synchronously until it completes. + * + * @param op operation to execute + * @throws WorldEditException WorldEdit exception + */ + public static void complete(Operation op) throws WorldEditException { + while (op != null) { + op = op.resume(new RunContext()); + } + } + + /** + * Complete a given operation synchronously until it completes. Catch all + * errors that is not {@link MaxChangedBlocksException} for legacy reasons. + * + * @param op operation to execute + * @throws MaxChangedBlocksException thrown when too many blocks have been changed + */ + public static void completeLegacy(Operation op) throws MaxChangedBlocksException { + while (op != null) { + try { + op = op.resume(new RunContext()); + } catch (MaxChangedBlocksException e) { + throw e; + } catch (WorldEditException e) { + throw new RuntimeException(e); + } + } + } + + /** + * Complete a given operation synchronously until it completes. Re-throw all + * {@link WorldEditException} exceptions as + * {@link RuntimeException}s. + * + * @param op operation to execute + */ + public static void completeBlindly(Operation op) { + while (op != null) { + try { + op = op.resume(new RunContext()); + } catch (WorldEditException e) { + throw new RuntimeException(e); + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/RunContext.java b/src/main/java/com/sk89q/worldedit/function/operation/RunContext.java new file mode 100644 index 0000000..404f549 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/RunContext.java @@ -0,0 +1,38 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.operation; + +/** + * Describes the current run. + */ +public class RunContext { + + /** + * Return whether the current operation should still continue running. + * + *

This method can be called frequently.

+ * + * @return true if the operation should continue running + */ + public boolean shouldContinue() { + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/SetBlockMap.java b/src/main/java/com/sk89q/worldedit/function/operation/SetBlockMap.java new file mode 100644 index 0000000..3284638 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/SetBlockMap.java @@ -0,0 +1,54 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.operation; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.collection.BlockMap; +import com.sk89q.worldedit.world.block.BaseBlock; + +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class SetBlockMap implements Operation { + + private final Extent extent; + private final BlockMap blocks; + + public SetBlockMap(Extent extent, BlockMap blocks) { + this.extent = checkNotNull(extent); + this.blocks = checkNotNull(blocks); + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + for (Map.Entry entry : blocks.entrySet()) { + extent.setBlock(entry.getKey(), entry.getValue()); + } + return null; + } + + @Override + public void cancel() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/SetLocatedBlocks.java b/src/main/java/com/sk89q/worldedit/function/operation/SetLocatedBlocks.java new file mode 100644 index 0000000..c7673f7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/SetLocatedBlocks.java @@ -0,0 +1,50 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.operation; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.LocatedBlock; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class SetLocatedBlocks implements Operation { + + private final Extent extent; + private final Iterable blocks; + + public SetLocatedBlocks(Extent extent, Iterable blocks) { + this.extent = checkNotNull(extent); + this.blocks = checkNotNull(blocks); + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + for (LocatedBlock block : blocks) { + extent.setBlock(block.getLocation(), block.getBlock()); + } + return null; + } + + @Override + public void cancel() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/AbstractExtentPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/AbstractExtentPattern.java new file mode 100644 index 0000000..4748c33 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/AbstractExtentPattern.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.extent.Extent; + +import static com.google.common.base.Preconditions.checkNotNull; + +public abstract class AbstractExtentPattern extends AbstractPattern implements ExtentPattern { + + private final Extent extent; + + public AbstractExtentPattern(Extent extent) { + this.extent = extent; + checkNotNull(extent); + } + + @Override + public Extent getExtent() { + return extent; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/AbstractPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/AbstractPattern.java new file mode 100644 index 0000000..c688663 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/AbstractPattern.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +/** + * An abstract implementation for {@link Pattern}s. + */ +public abstract class AbstractPattern implements Pattern { +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/BiomePattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/BiomePattern.java new file mode 100644 index 0000000..4dac73a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/BiomePattern.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; + +/** + * Returns a {@link BiomeType} for a given position. + */ +public interface BiomePattern { + + /** + * Return a {@link BiomeType} for the given position. + * + * @param position the position + * @return a biome + * @deprecated use {@link BiomePattern#applyBiome(BlockVector3)} + */ + @Deprecated + default BiomeType apply(BlockVector2 position) { + return applyBiome(position.toBlockVector3()); + } + + /** + * Return a {@link BiomeType} for the given position. + * + * @param position the position + * @return a biome + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "apply", + delegateParams = { BlockVector2.class } + ) + default BiomeType applyBiome(BlockVector3 position) { + DeprecationUtil.checkDelegatingOverride(getClass()); + + return apply(position.toBlockVector2()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java new file mode 100644 index 0000000..560fd0b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java @@ -0,0 +1,71 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A pattern that returns the same {@link BaseBlock} each time. + * + * @deprecated all BlockStateHolders can be used directly as a pattern + */ +@Deprecated +public class BlockPattern extends AbstractPattern { + + private BaseBlock block; + + /** + * Create a new pattern with the given block. + * + * @param block the block + */ + public BlockPattern(BlockStateHolder block) { + setBlock(block); + } + + /** + * Get the block. + * + * @return the block that is always returned + */ + public BaseBlock getBlock() { + return block; + } + + /** + * Set the block that is returned. + * + * @param block the block + */ + public void setBlock(BlockStateHolder block) { + checkNotNull(block); + this.block = block.toBaseBlock(); + } + + @Override + public BaseBlock applyBlock(BlockVector3 position) { + return block; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java new file mode 100644 index 0000000..08e5752 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java @@ -0,0 +1,48 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; + +/** + * A pattern that reads from {@link Clipboard}. + */ +public class ClipboardPattern extends RepeatingExtentPattern { + + /** + * Create a new clipboard pattern. + * + * @param clipboard the clipboard + */ + public ClipboardPattern(Clipboard clipboard) { + this(clipboard, BlockVector3.ZERO); + } + + /** + * Create a new clipboard pattern. + * + * @param clipboard the clipboard + * @param offset the offset + */ + public ClipboardPattern(Clipboard clipboard, BlockVector3 offset) { + super(clipboard, clipboard.getMinimumPoint(), offset); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java new file mode 100644 index 0000000..5583e55 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java @@ -0,0 +1,66 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.buffer.ExtentBuffer; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * A pattern that composes multiple patterns consecutively, ensuring that changes from one + * pattern are realized by the subsequent one(s). For best results, use an {@link ExtentBuffer} + * to avoid changing blocks in an underlying extent (e.g. the world). + */ +public class ExtentBufferedCompositePattern extends AbstractExtentPattern { + + private final Pattern[] patterns; + + /** + * Construct a new instance of this pattern. + * + *

Note that all patterns passed which are ExtentPatterns should use the same extent as the one + * passed to this constructor, or block changes may not be realized by those patterns.

+ * + * @param extent the extent to buffer changes to + * @param patterns the patterns to apply, in order + */ + public ExtentBufferedCompositePattern(Extent extent, Pattern... patterns) { + super(extent); + checkArgument(patterns.length != 0, "patterns cannot be empty"); + this.patterns = patterns; + } + + @Override + public BaseBlock applyBlock(BlockVector3 position) { + BaseBlock lastBlock = null; + for (Pattern pattern : patterns) { + lastBlock = pattern.applyBlock(position); + try { + getExtent().setBlock(position, lastBlock); + } catch (WorldEditException ignored) { // buffer doesn't throw + } + } + return lastBlock; + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/ExtentPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/ExtentPattern.java new file mode 100644 index 0000000..22a8f41 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/ExtentPattern.java @@ -0,0 +1,32 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.extent.Extent; + +public interface ExtentPattern extends Pattern { + + /** + * Get the extent associated with this pattern. + * + * @return the extent for this pattern + */ + Extent getExtent(); +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java new file mode 100644 index 0000000..70dd768 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; + +/** + * Returns a {@link BaseBlock} for a given position. + */ +public interface Pattern { + + /** + * Return a {@link BaseBlock} for the given position. + * + * @param position the position + * @return a block + * @deprecated use {@link Pattern#applyBlock(BlockVector3)} + */ + @Deprecated + default BaseBlock apply(BlockVector3 position) { + return applyBlock(position); + } + + /** + * Return a {@link BaseBlock} for the given position. + * + * @param position the position + * @return a block + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "apply", + delegateParams = { BlockVector3.class } + ) + default BaseBlock applyBlock(BlockVector3 position) { + DeprecationUtil.checkDelegatingOverride(getClass()); + + return apply(position); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java new file mode 100644 index 0000000..79ae212 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java @@ -0,0 +1,88 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Uses a random pattern of a weighted list of patterns. + */ +public class RandomPattern extends AbstractPattern { + + private final Random random = new Random(); + private final List patterns = new ArrayList<>(); + private double max = 0; + + /** + * Add a pattern to the weight list of patterns. + * + *

The probability for the pattern added is chance / max where max is + * the sum of the probabilities of all added patterns.

+ * + * @param pattern the pattern + * @param chance the chance, which can be any positive number + */ + public void add(Pattern pattern, double chance) { + checkNotNull(pattern); + patterns.add(new Chance(pattern, chance)); + max += chance; + } + + @Override + public BaseBlock applyBlock(BlockVector3 position) { + double r = random.nextDouble(); + double offset = 0; + + for (Chance chance : patterns) { + if (r <= (offset + chance.getChance()) / max) { + return chance.getPattern().applyBlock(position); + } + offset += chance.getChance(); + } + + throw new RuntimeException("ProportionalFillPattern"); + } + + private static class Chance { + private final Pattern pattern; + private final double chance; + + private Chance(Pattern pattern, double chance) { + this.pattern = pattern; + this.chance = chance; + } + + public Pattern getPattern() { + return pattern; + } + + public double getChance() { + return chance; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/RandomStatePattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/RandomStatePattern.java new file mode 100644 index 0000000..65e0633 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/RandomStatePattern.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.FuzzyBlockState; + +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +public class RandomStatePattern implements Pattern { + + private final Random rand = new Random(); + private final List blocks; + + public RandomStatePattern(FuzzyBlockState state) { + blocks = state.getBlockType().getAllStates().stream().filter(state::equalsFuzzy) + .map(BlockState::toBaseBlock).collect(Collectors.toList()); + } + + @Override + public BaseBlock applyBlock(BlockVector3 position) { + return blocks.get(rand.nextInt(blocks.size())); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java new file mode 100644 index 0000000..6dd62b7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java @@ -0,0 +1,97 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Returns the blocks from {@link Extent}, repeating when out of bounds. + */ +public class RepeatingExtentPattern extends AbstractExtentPattern { + + private final BlockVector3 size; + private BlockVector3 origin; + private BlockVector3 offset; + + /** + * Create a new instance. + * + * @param extent the extent + * @param offset the offset + */ + public RepeatingExtentPattern(Extent extent, BlockVector3 origin, BlockVector3 offset) { + super(extent); + setOrigin(origin); + setOffset(offset); + size = extent.getMaximumPoint().subtract(extent.getMinimumPoint()).add(1, 1, 1); + } + + /** + * Get the offset. + * + * @return the offset + */ + public BlockVector3 getOffset() { + return offset; + } + + /** + * Set the offset. + * + * @param offset the offset + */ + public void setOffset(BlockVector3 offset) { + checkNotNull(offset); + this.offset = offset; + } + + /** + * Get the origin. + * + * @return the origin + */ + public BlockVector3 getOrigin() { + return origin; + } + + /** + * Set the origin. + * + * @param origin the origin + */ + public void setOrigin(BlockVector3 origin) { + checkNotNull(origin); + this.origin = origin; + } + + @Override + public BaseBlock applyBlock(BlockVector3 position) { + BlockVector3 base = position.add(offset); + int x = Math.floorMod(base.getBlockX(), size.getBlockX()); + int y = Math.floorMod(base.getBlockY(), size.getBlockY()); + int z = Math.floorMod(base.getBlockZ(), size.getBlockZ()); + return getExtent().getFullBlock(BlockVector3.at(x, y, z).add(origin)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java new file mode 100644 index 0000000..2635d2f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java @@ -0,0 +1,54 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.google.common.collect.Maps; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.Map; +import java.util.Map.Entry; + +import static com.sk89q.worldedit.blocks.Blocks.resolveProperties; + +public class StateApplyingPattern extends AbstractExtentPattern { + + private final Map states; + private final Map, Object>> cache = Maps.newHashMap(); + + public StateApplyingPattern(Extent extent, Map statesToSet) { + super(extent); + this.states = statesToSet; + } + + @Override + public BaseBlock applyBlock(BlockVector3 position) { + BlockState block = getExtent().getBlock(position); + for (Entry, Object> entry : cache + .computeIfAbsent(block.getBlockType(), (b -> resolveProperties(states, b))).entrySet()) { + block = block.with(entry.getKey(), entry.getValue()); + } + return block.toBaseBlock(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/TypeApplyingPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/TypeApplyingPattern.java new file mode 100644 index 0000000..31a6276 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/TypeApplyingPattern.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +import java.util.Map.Entry; + +/** + * Applies a block type while retaining all possible states. + */ +public class TypeApplyingPattern extends AbstractExtentPattern { + private final BlockState blockState; + + public TypeApplyingPattern(Extent extent, BlockState blockState) { + super(extent); + this.blockState = blockState; + } + + @Override + public BaseBlock applyBlock(BlockVector3 position) { + BlockState oldBlock = getExtent().getBlock(position); + BlockState newBlock = blockState; + for (Entry, Object> entry : oldBlock.getStates().entrySet()) { + @SuppressWarnings("unchecked") + Property prop = (Property) entry.getKey(); + newBlock = newBlock.with(prop, entry.getValue()); + } + return newBlock.toBaseBlock(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/WaterloggedRemover.java b/src/main/java/com/sk89q/worldedit/function/pattern/WaterloggedRemover.java new file mode 100644 index 0000000..533f937 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/WaterloggedRemover.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.pattern; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockTypes; + +/** + * Removes the waterlogged state from blocks if possible. If not possible, returns air. + */ +public class WaterloggedRemover extends AbstractExtentPattern { + + public WaterloggedRemover(Extent extent) { + super(extent); + } + + @Override + public BaseBlock applyBlock(BlockVector3 position) { + BaseBlock block = getExtent().getFullBlock(position); + @SuppressWarnings("unchecked") + Property prop = (Property) block.getBlockType().getPropertyMap().getOrDefault("waterlogged", null); + if (prop != null) { + return block.with(prop, false); + } + return BlockTypes.AIR.getDefaultState().toBaseBlock(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/util/FlatRegionOffset.java b/src/main/java/com/sk89q/worldedit/function/util/FlatRegionOffset.java new file mode 100644 index 0000000..7b25655 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/util/FlatRegionOffset.java @@ -0,0 +1,71 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.util; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.FlatRegionFunction; +import com.sk89q.worldedit.math.BlockVector2; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Offsets the position parameter by adding a given offset vector. + */ +public class FlatRegionOffset implements FlatRegionFunction { + + private BlockVector2 offset; + private final FlatRegionFunction function; + + /** + * Create a new instance. + * + * @param offset the offset + * @param function the function that is called with the offset position + */ + public FlatRegionOffset(BlockVector2 offset, FlatRegionFunction function) { + checkNotNull(function); + setOffset(offset); + this.function = function; + } + + /** + * Get the offset that is added to the position. + * + * @return the offset + */ + public BlockVector2 getOffset() { + return offset; + } + + /** + * Set the offset that is added to the position. + * + * @param offset the offset + */ + public void setOffset(BlockVector2 offset) { + checkNotNull(offset); + this.offset = offset; + } + + @Override + public boolean apply(BlockVector2 position) throws WorldEditException { + return function.apply(position.add(offset)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/util/RegionOffset.java b/src/main/java/com/sk89q/worldedit/function/util/RegionOffset.java new file mode 100644 index 0000000..ec28344 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/util/RegionOffset.java @@ -0,0 +1,72 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.util; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.BlockVector3; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Offsets the position parameter by adding a given offset vector. + */ +public class RegionOffset implements RegionFunction { + + private BlockVector3 offset; + private final RegionFunction function; + + /** + * Create a new instance. + * + * @param offset the offset + * @param function the function that is called with the offset position + */ + public RegionOffset(BlockVector3 offset, RegionFunction function) { + checkNotNull(function); + setOffset(offset); + this.function = function; + } + + /** + * Get the offset that is added to the position. + * + * @return the offset + */ + public BlockVector3 getOffset() { + return offset; + } + + /** + * Set the offset that is added to the position. + * + * @param offset the offset + */ + public void setOffset(BlockVector3 offset) { + checkNotNull(offset); + this.offset = offset; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + return function.apply(position.add(offset)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java b/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java new file mode 100644 index 0000000..9339680 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java @@ -0,0 +1,190 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.visitor; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; + +import java.util.*; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Performs a breadth-first search starting from points added with + * {@link #visit(BlockVector3)}. The search continues + * to a certain adjacent point provided that the method + * {@link #isVisitable(BlockVector3, BlockVector3)} + * returns true for that point. + * + *

As an abstract implementation, this class can be used to implement + * functionality that starts at certain points and extends outward from + * those points.

+ */ +public abstract class BreadthFirstSearch implements Operation { + + private final RegionFunction function; + private final Queue queue = new ArrayDeque<>(); + private final Set visited = new HashSet<>(); + private final List directions = new ArrayList<>(); + private int affected = 0; + + /** + * Create a new instance. + * + * @param function the function to apply to visited blocks + */ + protected BreadthFirstSearch(RegionFunction function) { + checkNotNull(function); + this.function = function; + addAxes(); + } + + /** + * Get the list of directions will be visited. + * + *

Directions are {@link BlockVector3}s that determine + * what adjacent points area available. Vectors should not be + * unit vectors. An example of a valid direction is + * {@code BlockVector3.at(1, 0, 1)}.

+ * + *

The list of directions can be cleared.

+ * + * @return the list of directions + */ + protected Collection getDirections() { + return directions; + } + + /** + * Add the directions along the axes as directions to visit. + */ + protected void addAxes() { + directions.add(BlockVector3.UNIT_MINUS_Y); + directions.add(BlockVector3.UNIT_Y); + directions.add(BlockVector3.UNIT_MINUS_X); + directions.add(BlockVector3.UNIT_X); + directions.add(BlockVector3.UNIT_MINUS_Z); + directions.add(BlockVector3.UNIT_Z); + } + + /** + * Add the diagonal directions as directions to visit. + */ + protected void addDiagonal() { + directions.add(Direction.NORTHEAST.toBlockVector()); + directions.add(Direction.SOUTHEAST.toBlockVector()); + directions.add(Direction.SOUTHWEST.toBlockVector()); + directions.add(Direction.NORTHWEST.toBlockVector()); + } + + /** + * Add the given location to the list of locations to visit, provided + * that it has not been visited. The position passed to this method + * will still be visited even if it fails + * {@link #isVisitable(BlockVector3, BlockVector3)}. + * + *

This method should be used before the search begins, because if + * the position does fail the test, and the search has already + * visited it (because it is connected to another root point), + * the search will mark the position as "visited" and a call to this + * method will do nothing.

+ * + * @param position the position + */ + public void visit(BlockVector3 position) { + if (!visited.contains(position)) { + queue.add(position); + visited.add(position); + } + } + + /** + * Try to visit the given 'to' location. + * + * @param from the origin block + * @param to the block under question + */ + private void visit(BlockVector3 from, BlockVector3 to) { + if (!visited.contains(to)) { + visited.add(to); + if (isVisitable(from, to)) { + queue.add(to); + } + } + } + + /** + * Return whether the given 'to' block should be visited, starting from the + * 'from' block. + * + * @param from the origin block + * @param to the block under question + * @return true if the 'to' block should be visited + */ + protected abstract boolean isVisitable(BlockVector3 from, BlockVector3 to); + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + BlockVector3 position; + + while ((position = queue.poll()) != null) { + if (function.apply(position)) { + affected++; + } + + for (BlockVector3 dir : directions) { + visit(position, position.add(dir)); + } + } + + return null; + } + + @Override + public void cancel() { + } + + @Override + public Iterable getStatusMessages() { + return ImmutableList.of(TranslatableComponent.of( + "worldedit.operation.affected.block", + TextComponent.of(getAffected()) + ).color(TextColor.LIGHT_PURPLE)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java new file mode 100644 index 0000000..4a11084 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.visitor; + +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; + +import java.util.Collection; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Visits adjacent points on the same X-Z plane as long as the points + * pass the given mask, and then executes the provided region + * function on the entire column. + * + *

This is used by {@code //fill}.

+ */ +public class DownwardVisitor extends RecursiveVisitor { + + private final int baseY; + + /** + * Create a new visitor. + * + * @param mask the mask + * @param function the function + * @param baseY the base Y + */ + public DownwardVisitor(Mask mask, RegionFunction function, int baseY) { + super(mask, function); + checkNotNull(mask); + + this.baseY = baseY; + + Collection directions = getDirections(); + directions.clear(); + directions.add(BlockVector3.UNIT_X); + directions.add(BlockVector3.UNIT_MINUS_X); + directions.add(BlockVector3.UNIT_Z); + directions.add(BlockVector3.UNIT_MINUS_Z); + directions.add(BlockVector3.UNIT_MINUS_Y); + } + + @Override + protected boolean isVisitable(BlockVector3 from, BlockVector3 to) { + int fromY = from.getBlockY(); + return (fromY == baseY || to.subtract(from).getBlockY() < 0) && super.isVisitable(from, to); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java new file mode 100644 index 0000000..a560ab1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/EntityVisitor.java @@ -0,0 +1,91 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.visitor; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.EntityFunction; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; + +import java.util.Iterator; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Visits entities as provided by an {@code Iterator}. + */ +public class EntityVisitor implements Operation { + + private final Iterator iterator; + private final EntityFunction function; + private int affected = 0; + + /** + * Create a new instance. + * + * @param iterator the iterator + * @param function the function + */ + public EntityVisitor(Iterator iterator, EntityFunction function) { + checkNotNull(iterator); + checkNotNull(function); + this.iterator = iterator; + this.function = function; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + while (iterator.hasNext()) { + if (function.apply(iterator.next())) { + affected++; + } + } + + return null; + } + + @Override + public void cancel() { + } + + @Override + public Iterable getStatusMessages() { + return ImmutableList.of(TranslatableComponent.of( + "worldedit.operation.affected.entity", + TextComponent.of(getAffected()) + ).color(TextColor.LIGHT_PURPLE)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/FlatRegionVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/FlatRegionVisitor.java new file mode 100644 index 0000000..525e33a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/FlatRegionVisitor.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.visitor; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.FlatRegionFunction; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.regions.FlatRegion; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Applies region functions to columns in a {@link FlatRegion}. + */ +public class FlatRegionVisitor implements Operation { + + private final FlatRegion flatRegion; + private final FlatRegionFunction function; + private int affected = 0; + + /** + * Create a new visitor. + * + * @param flatRegion a flat region + * @param function a function to apply to columns + */ + public FlatRegionVisitor(FlatRegion flatRegion, FlatRegionFunction function) { + checkNotNull(flatRegion); + checkNotNull(function); + + this.flatRegion = flatRegion; + this.function = function; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + for (BlockVector2 pt : flatRegion.asFlatRegion()) { + if (function.apply(pt)) { + affected++; + } + } + + return null; + } + + @Override + public void cancel() { + } + + @Override + public Iterable getStatusMessages() { + return ImmutableList.of(TranslatableComponent.of( + "worldedit.operation.affected.column", + TextComponent.of(getAffected()) + ).color(TextColor.LIGHT_PURPLE)); + } + +} + diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java new file mode 100644 index 0000000..c5acd33 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java @@ -0,0 +1,129 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.visitor; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.LayerFunction; +import com.sk89q.worldedit.function.mask.Mask2D; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.FlatRegion; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Visits the layers within a region. + * + *

This class works by iterating over all the columns in a {@link FlatRegion}, + * finding the first ground block in each column (searching from a given + * maximum Y down to a minimum Y), and then applies a {@link LayerFunction} to + * each layer.

+ */ +public class LayerVisitor implements Operation { + + private final FlatRegion flatRegion; + private final LayerFunction function; + private Mask2D mask = Masks.alwaysTrue2D(); + private final int minY; + private final int maxY; + + /** + * Create a new visitor. + * + * @param flatRegion the flat region to visit + * @param minY the minimum Y to stop the search at + * @param maxY the maximum Y to begin the search at + * @param function the layer function to apply t blocks + */ + public LayerVisitor(FlatRegion flatRegion, int minY, int maxY, LayerFunction function) { + checkNotNull(flatRegion); + checkArgument(minY <= maxY, "minY <= maxY required"); + checkNotNull(function); + + this.flatRegion = flatRegion; + this.minY = minY; + this.maxY = maxY; + this.function = function; + } + + /** + * Get the mask that determines which columns within the flat region + * will be visited. + * + * @return a 2D mask + */ + public Mask2D getMask() { + return mask; + } + + /** + * Set the mask that determines which columns within the flat region + * will be visited. + * + * @param mask a 2D mask + */ + public void setMask(Mask2D mask) { + checkNotNull(mask); + this.mask = mask; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + for (BlockVector2 column : flatRegion.asFlatRegion()) { + if (!mask.test(column)) { + continue; + } + + // Abort if we are underground + if (function.isGround(column.toBlockVector3(maxY + 1))) { + continue; + } + + boolean found = false; + int groundY = 0; + for (int y = maxY; y >= minY; --y) { + BlockVector3 test = column.toBlockVector3(y); + if (!found) { + if (function.isGround(test)) { + found = true; + groundY = y; + } + } + + if (found) { + if (!function.apply(test, groundY - y)) { + break; + } + } + } + } + + return null; + } + + @Override + public void cancel() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java new file mode 100644 index 0000000..ad64b53 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java @@ -0,0 +1,50 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.visitor; + +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; + +import java.util.Collection; + +/** + * A {@link RecursiveVisitor} that goes orthogonally to the side and down, but never up. + */ +public class NonRisingVisitor extends RecursiveVisitor { + + /** + * Create a new recursive visitor. + * + * @param mask the mask + * @param function the function + */ + public NonRisingVisitor(Mask mask, RegionFunction function) { + super(mask, function); + Collection directions = getDirections(); + directions.clear(); + directions.add(BlockVector3.UNIT_X); + directions.add(BlockVector3.UNIT_MINUS_X); + directions.add(BlockVector3.UNIT_Z); + directions.add(BlockVector3.UNIT_MINUS_Z); + directions.add(BlockVector3.UNIT_MINUS_Y); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java new file mode 100644 index 0000000..bf9462e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.visitor; + +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An implementation of an {@link BreadthFirstSearch} that uses a mask to + * determine where a block should be visited. + */ +public class RecursiveVisitor extends BreadthFirstSearch { + + private final Mask mask; + + /** + * Create a new recursive visitor. + * + * @param mask the mask + * @param function the function + */ + public RecursiveVisitor(Mask mask, RegionFunction function) { + super(function); + checkNotNull(mask); + this.mask = mask; + } + + @Override + protected boolean isVisitable(BlockVector3 from, BlockVector3 to) { + return mask.test(to); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java new file mode 100644 index 0000000..052180a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.function.visitor; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.format.TextColor; + +/** + * Utility class to apply region functions to {@link Region}. + */ +public class RegionVisitor implements Operation { + + private final Region region; + private final RegionFunction function; + private int affected = 0; + + public RegionVisitor(Region region, RegionFunction function) { + this.region = region; + this.function = function; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + for (BlockVector3 pt : region) { + if (function.apply(pt)) { + affected++; + } + } + + return null; + } + + @Override + public void cancel() { + } + + @Override + public Iterable getStatusMessages() { + return ImmutableList.of(TranslatableComponent.of( + "worldedit.operation.affected.block", + TextComponent.of(getAffected()) + ).color(TextColor.LIGHT_PURPLE)); + } + +} + diff --git a/src/main/java/com/sk89q/worldedit/history/UndoContext.java b/src/main/java/com/sk89q/worldedit/history/UndoContext.java new file mode 100644 index 0000000..08f7085 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/UndoContext.java @@ -0,0 +1,54 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.history; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.history.change.BlockChange; + +import javax.annotation.Nullable; + +/** + * Provides context for undo and redo operations. + * + *

For example, {@link BlockChange}s take the {@link Extent} from the + * context rather than store a reference to one.

+ */ +public class UndoContext { + + private Extent extent; + + /** + * Get the extent set on this context. + * + * @return an extent or null + */ + public @Nullable Extent getExtent() { + return extent; + } + + /** + * Set the extent on this context. + * + * @param extent an extent or null + */ + public void setExtent(@Nullable Extent extent) { + this.extent = extent; + } +} diff --git a/src/main/java/com/sk89q/worldedit/history/change/BiomeChange.java b/src/main/java/com/sk89q/worldedit/history/change/BiomeChange.java new file mode 100644 index 0000000..634dd31 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/change/BiomeChange.java @@ -0,0 +1,98 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.history.change; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.world.biome.BiomeType; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a biome change that may be undone or replayed. + * + *

This biome change does not have an {@link Extent} assigned to it because + * one will be taken from the passed {@link UndoContext}. If the context + * does not have an extent (it is null), cryptic errors may occur.

+ * @deprecated use {@link BiomeChange3D} + */ +@Deprecated +public class BiomeChange implements Change { + + private final BlockVector2 position; + private final BiomeType previous; + private final BiomeType current; + + /** + * Create a new biome change. + * + * @param position the position + * @param previous the previous biome + * @param current the current biome + */ + public BiomeChange(BlockVector2 position, BiomeType previous, BiomeType current) { + checkNotNull(position); + checkNotNull(previous); + checkNotNull(current); + this.position = position; + this.previous = previous; + this.current = current; + } + + /** + * Get the position. + * + * @return the position + */ + public BlockVector2 getPosition() { + return position; + } + + /** + * Get the previous biome. + * + * @return the previous biome + */ + public BiomeType getPrevious() { + return previous; + } + + /** + * Get the current biome. + * + * @return the current biome + */ + public BiomeType getCurrent() { + return current; + } + + @Override + public void undo(UndoContext context) throws WorldEditException { + checkNotNull(context.getExtent()).setBiome(position.toBlockVector3(), previous); + } + + @Override + public void redo(UndoContext context) throws WorldEditException { + checkNotNull(context.getExtent()).setBiome(position.toBlockVector3(), current); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java b/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java new file mode 100644 index 0000000..6b40127 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java @@ -0,0 +1,96 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.history.change; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a biome change that may be undone or replayed. + * + *

This biome change does not have an {@link Extent} assigned to it because + * one will be taken from the passed {@link UndoContext}. If the context + * does not have an extent (it is null), cryptic errors may occur.

+ */ +public class BiomeChange3D implements Change { + + private final BlockVector3 position; + private final BiomeType previous; + private final BiomeType current; + + /** + * Create a new biome change. + * + * @param position the position + * @param previous the previous biome + * @param current the current biome + */ + public BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType current) { + checkNotNull(position); + checkNotNull(previous); + checkNotNull(current); + this.position = position; + this.previous = previous; + this.current = current; + } + + /** + * Get the position. + * + * @return the position + */ + public BlockVector3 getPosition() { + return position; + } + + /** + * Get the previous biome. + * + * @return the previous biome + */ + public BiomeType getPrevious() { + return previous; + } + + /** + * Get the current biome. + * + * @return the current biome + */ + public BiomeType getCurrent() { + return current; + } + + @Override + public void undo(UndoContext context) throws WorldEditException { + checkNotNull(context.getExtent()).setBiome(position, previous); + } + + @Override + public void redo(UndoContext context) throws WorldEditException { + checkNotNull(context.getExtent()).setBiome(position, current); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java b/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java new file mode 100644 index 0000000..0b01508 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java @@ -0,0 +1,97 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.history.change; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a block change that may be undone or replayed. + * + *

This block change does not have an {@link Extent} assigned to it because + * one will be taken from the passed {@link UndoContext}. If the context + * does not have an extent (it is null), cryptic errors may occur.

+ */ +public class BlockChange implements Change { + + private final BlockVector3 position; + private final BaseBlock previous; + private final BaseBlock current; + + /** + * Create a new block change. + * + * @param position the position + * @param previous the previous block + * @param current the current block + */ + public , BC extends BlockStateHolder> BlockChange(BlockVector3 position, BP previous, BC current) { + checkNotNull(position); + checkNotNull(previous); + checkNotNull(current); + this.position = position; + this.previous = previous.toBaseBlock(); + this.current = current.toBaseBlock(); + } + + /** + * Get the position. + * + * @return the position + */ + public BlockVector3 getPosition() { + return position; + } + + /** + * Get the previous block. + * + * @return the previous block + */ + public BaseBlock getPrevious() { + return previous; + } + + /** + * Get the current block. + * + * @return the current block + */ + public BaseBlock getCurrent() { + return current; + } + + @Override + public void undo(UndoContext context) throws WorldEditException { + checkNotNull(context.getExtent()).setBlock(position, previous); + } + + @Override + public void redo(UndoContext context) throws WorldEditException { + checkNotNull(context.getExtent()).setBlock(position, current); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/history/change/Change.java b/src/main/java/com/sk89q/worldedit/history/change/Change.java new file mode 100644 index 0000000..5808f97 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/change/Change.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.history.change; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.history.changeset.ChangeSet; + +/** + * Describes a change that can be undone or re-applied. + */ +public interface Change { + + /** + * Perform an undo. This method may not be available if the object + * was returned from {@link ChangeSet#forwardIterator()}. + * + * @param context a context for undo + * @throws WorldEditException on an error + */ + void undo(UndoContext context) throws WorldEditException; + + /** + * Perform an redo. This method may not be available if the object + * was returned from {@link ChangeSet#backwardIterator()} ()}. + * + * @param context a context for redo + * @throws WorldEditException on an error + */ + void redo(UndoContext context) throws WorldEditException; + +} diff --git a/src/main/java/com/sk89q/worldedit/history/change/EntityCreate.java b/src/main/java/com/sk89q/worldedit/history/change/EntityCreate.java new file mode 100644 index 0000000..7200d81 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/change/EntityCreate.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.history.change; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.util.Location; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Logs the creation of an entity and removes the entity upon undo. + */ +public class EntityCreate implements Change { + + private final Location location; + private final BaseEntity state; + private Entity entity; + + /** + * Create a new instance. + * + * @param location the location + * @param state the state of the created entity + * @param entity the entity that was created + */ + public EntityCreate(Location location, BaseEntity state, Entity entity) { + checkNotNull(location); + checkNotNull(state); + checkNotNull(entity); + this.location = location; + this.state = state; + this.entity = entity; + } + + @Override + public void undo(UndoContext context) throws WorldEditException { + if (entity != null) { + entity.remove(); + entity = null; + } + } + + @Override + public void redo(UndoContext context) throws WorldEditException { + entity = checkNotNull(context.getExtent()).createEntity(location, state); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/history/change/EntityRemove.java b/src/main/java/com/sk89q/worldedit/history/change/EntityRemove.java new file mode 100644 index 0000000..fe6c82b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/change/EntityRemove.java @@ -0,0 +1,65 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.history.change; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.util.Location; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Tracks the removal of an entity. + */ +public class EntityRemove implements Change { + + private final Location location; + private final BaseEntity state; + private Entity entity; + + /** + * Create a new instance. + * + * @param location the location + * @param state the state of the created entity + */ + public EntityRemove(Location location, BaseEntity state) { + checkNotNull(location); + checkNotNull(state); + this.location = location; + this.state = state; + } + + @Override + public void undo(UndoContext context) throws WorldEditException { + entity = checkNotNull(context.getExtent()).createEntity(location, state); + } + + @Override + public void redo(UndoContext context) throws WorldEditException { + if (entity != null) { + entity.remove(); + entity = null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java b/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java new file mode 100644 index 0000000..18dbee7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java @@ -0,0 +1,73 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.history.changeset; + +import com.google.common.collect.Lists; +import com.sk89q.worldedit.history.change.Change; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Stores all {@link Change}s in an {@link ArrayList}. + */ +public class ArrayListHistory implements ChangeSet { + + private final List changes = new ArrayList<>(); + + private boolean recordChanges = true; + + @Override + public void add(Change change) { + checkNotNull(change); + if (recordChanges) { + changes.add(change); + } + } + + @Override + public boolean isRecordingChanges() { + return recordChanges; + } + + @Override + public void setRecordChanges(boolean recordChanges) { + this.recordChanges = recordChanges; + } + + @Override + public Iterator backwardIterator() { + return Lists.reverse(changes).iterator(); + } + + @Override + public Iterator forwardIterator() { + return changes.iterator(); + } + + @Override + public int size() { + return changes.size(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java b/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java new file mode 100644 index 0000000..995679f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java @@ -0,0 +1,85 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.history.changeset; + +import com.google.common.collect.Iterators; +import com.sk89q.worldedit.history.change.BlockChange; +import com.sk89q.worldedit.history.change.Change; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.LocatedBlock; +import com.sk89q.worldedit.util.collection.LocatedBlockList; + +import java.util.ArrayList; +import java.util.Iterator; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An extension of {@link ArrayListHistory} that stores {@link BlockChange}s + * separately in two {@link ArrayList}s. + * + *

Whether this is a good idea or not is highly questionable, but this class + * exists because this is how history was implemented in WorldEdit for + * many years.

+ */ +public class BlockOptimizedHistory extends ArrayListHistory { + + private static Change createChange(LocatedBlock block) { + return new BlockChange(block.getLocation(), block.getBlock(), block.getBlock()); + } + + private final LocatedBlockList previous = new LocatedBlockList(); + private final LocatedBlockList current = new LocatedBlockList(); + + @Override + public void add(Change change) { + checkNotNull(change); + + if (change instanceof BlockChange) { + BlockChange blockChange = (BlockChange) change; + BlockVector3 position = blockChange.getPosition(); + if (!previous.containsLocation(position)) { + previous.add(position, blockChange.getPrevious()); + } + current.add(position, blockChange.getCurrent()); + } else { + super.add(change); + } + } + + @Override + public Iterator forwardIterator() { + return Iterators.concat( + super.forwardIterator(), + Iterators.transform(current.iterator(), BlockOptimizedHistory::createChange)); + } + + @Override + public Iterator backwardIterator() { + return Iterators.concat( + super.backwardIterator(), + Iterators.transform(previous.reverseIterator(), BlockOptimizedHistory::createChange)); + } + + @Override + public int size() { + return super.size() + previous.size(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java b/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java new file mode 100644 index 0000000..e877740 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java @@ -0,0 +1,80 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.history.changeset; + +import com.sk89q.worldedit.history.change.Change; + +import java.util.Iterator; + +/** + * Tracks a set of undoable operations and allows their undo and redo. The + * entirety of a change set should be undone and redone at once. + */ +public interface ChangeSet { + + /** + * Add the given change to the history. + * + * @param change the change + */ + void add(Change change); + + /** + * Whether or not the ChangeSet is recording changes. + * + * @return whether or not the ChangeSet is set to record changes + */ + boolean isRecordingChanges(); + + /** + * Tell the change set whether to record changes or not. + * + * @param recordChanges whether to record changes or not + */ + void setRecordChanges(boolean recordChanges); + + /** + * Get a backward directed iterator that can be used for undo. + * + *

The iterator may return the changes out of order, as long as the final + * result after all changes have been applied is correct.

+ * + * @return a undo directed iterator + */ + Iterator backwardIterator(); + + /** + * Get a forward directed iterator that can be used for redo. + * + *

The iterator may return the changes out of order, as long as the final + * result after all changes have been applied is correct.

+ * + * @return a forward directed iterator + */ + Iterator forwardIterator(); + + /** + * Get the number of stored changes. + * + * @return the change count + */ + int size(); + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/Constants.java b/src/main/java/com/sk89q/worldedit/internal/Constants.java new file mode 100644 index 0000000..d6ff64d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/Constants.java @@ -0,0 +1,90 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public final class Constants { + + private Constants() { + } + + /** + * List of top level NBT fields that should not be copied to a world, + * such as UUIDLeast and UUIDMost. + */ + public static final List NO_COPY_ENTITY_NBT_FIELDS; + + static { + NO_COPY_ENTITY_NBT_FIELDS = Collections.unmodifiableList(Arrays.asList( + "UUIDLeast", "UUIDMost", "UUID", // Bukkit and Vanilla + "WorldUUIDLeast", "WorldUUIDMost", // Bukkit and Vanilla + "PersistentIDMSB", "PersistentIDLSB" // Forge + )); + } + + /** + * The DataVersion for Minecraft 1.13 + */ + public static final int DATA_VERSION_MC_1_13 = 1519; + + /** + * The DataVersion for Minecraft 1.13.2 + */ + public static final int DATA_VERSION_MC_1_13_2 = 1631; + + /** + * The DataVersion for Minecraft 1.14 + */ + public static final int DATA_VERSION_MC_1_14 = 1952; + + /** + * The DataVersion for Minecraft 1.15 + */ + public static final int DATA_VERSION_MC_1_15 = 2225; + + /** + * The DataVersion for Minecraft 1.16 + */ + public static final int DATA_VERSION_MC_1_16 = 2566; + + /** + * The DataVersion for Minecraft 1.17 + */ + public static final int DATA_VERSION_MC_1_17 = 2724; + + /** + * The DataVersion for Minecraft 1.18 + */ + public static final int DATA_VERSION_MC_1_18 = 2860; + + /** + * The DataVersion for Minecraft 1.19 + */ + public static final int DATA_VERSION_MC_1_19 = 3105; + + /** + * The DataVersion for Minecraft 1.20 + */ + public static final int DATA_VERSION_MC_1_20 = 3463; + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/SchematicsEventListener.java b/src/main/java/com/sk89q/worldedit/internal/SchematicsEventListener.java new file mode 100644 index 0000000..388953d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/SchematicsEventListener.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal; + +import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.util.eventbus.Subscribe; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class SchematicsEventListener { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + @Subscribe + public void onConfigLoad(ConfigurationLoadEvent event) { + Path config = event.getConfiguration().getWorkingDirectory().toPath(); + try { + Files.createDirectories(config.resolve(event.getConfiguration().saveDir)); + } catch (FileAlreadyExistsException e) { + LOGGER.debug("Schematic directory exists as file. Possible symlink.", e); + } catch (IOException e) { + LOGGER.warn("Failed to create schematics directory", e); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/annotation/Chunk3d.java b/src/main/java/com/sk89q/worldedit/internal/annotation/Chunk3d.java new file mode 100644 index 0000000..e97c3dd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/annotation/Chunk3d.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.annotation; + +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that this value is for 3d-chunk compatibility. + * + *

+ * For vectors, this means that the vector supports 2D & 3D inputs, + * with 2D getting a Y value of 0. + *

+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface Chunk3d { +} diff --git a/src/main/java/com/sk89q/worldedit/internal/annotation/ClipboardMask.java b/src/main/java/com/sk89q/worldedit/internal/annotation/ClipboardMask.java new file mode 100644 index 0000000..a032575 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/annotation/ClipboardMask.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.annotation; + +import com.sk89q.worldedit.function.mask.Mask; +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates a {@link Mask} parameter to use the clipboard as the extent instead of target World/EditSession. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface ClipboardMask { +} diff --git a/src/main/java/com/sk89q/worldedit/internal/annotation/Direction.java b/src/main/java/com/sk89q/worldedit/internal/annotation/Direction.java new file mode 100644 index 0000000..69a6eb7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/annotation/Direction.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.annotation; + +import com.sk89q.worldedit.math.BlockVector3; +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates a {@link BlockVector3} parameter to inject a direction. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface Direction { + + String AIM = "me"; + + boolean includeDiagonals() default false; +} diff --git a/src/main/java/com/sk89q/worldedit/internal/annotation/MultiDirection.java b/src/main/java/com/sk89q/worldedit/internal/annotation/MultiDirection.java new file mode 100644 index 0000000..c238589 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/annotation/MultiDirection.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.annotation; + +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates a {@code List} parameter to inject multiple direction. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface MultiDirection { + boolean includeDiagonals() default false; +} diff --git a/src/main/java/com/sk89q/worldedit/internal/annotation/Offset.java b/src/main/java/com/sk89q/worldedit/internal/annotation/Offset.java new file mode 100644 index 0000000..0772402 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/annotation/Offset.java @@ -0,0 +1,38 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.annotation; + +import com.sk89q.worldedit.math.BlockVector3; +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates a {@link BlockVector3} parameter to inject an offset. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface Offset { + String FORWARD = "forward"; +} diff --git a/src/main/java/com/sk89q/worldedit/internal/annotation/OptionalArg.java b/src/main/java/com/sk89q/worldedit/internal/annotation/OptionalArg.java new file mode 100644 index 0000000..1514a66 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/annotation/OptionalArg.java @@ -0,0 +1,38 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.annotation; + +import com.sk89q.worldedit.entity.Player; +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates a parameter to indicate it as optional. This is really a bit of a hack, used to + * get a {@link Player} or {@code null} instead of throwing. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface OptionalArg { +} diff --git a/src/main/java/com/sk89q/worldedit/internal/annotation/Radii.java b/src/main/java/com/sk89q/worldedit/internal/annotation/Radii.java new file mode 100644 index 0000000..4678836 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/annotation/Radii.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.annotation; + +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates a {@code double} parameter to inject multiple radii values. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface Radii { + /** + * Number of radii values to inject at maximum. May inject less. + */ + int value(); +} diff --git a/src/main/java/com/sk89q/worldedit/internal/annotation/Selection.java b/src/main/java/com/sk89q/worldedit/internal/annotation/Selection.java new file mode 100644 index 0000000..4bf8183 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/annotation/Selection.java @@ -0,0 +1,36 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.annotation; + +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that this value should come from the current selection. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface Selection { +} diff --git a/src/main/java/com/sk89q/worldedit/internal/annotation/VertHeight.java b/src/main/java/com/sk89q/worldedit/internal/annotation/VertHeight.java new file mode 100644 index 0000000..38f4bb1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/annotation/VertHeight.java @@ -0,0 +1,36 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.annotation; + +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that this value is for holding the vertical height. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface VertHeight { +} diff --git a/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java b/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java new file mode 100644 index 0000000..71f5e5a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java @@ -0,0 +1,362 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.anvil; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonIOException; +import com.google.gson.JsonSyntaxException; +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector2; +import org.apache.logging.log4j.Logger; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.BiPredicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class ChunkDeleter { + + public static final String DELCHUNKS_FILE_NAME = "delete_chunks.json"; + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final Comparator chunkSorter = Comparator.comparing( + pos -> (pos.getBlockX() & 31) + (pos.getBlockZ() & 31) * 32 + ); + + private static final Gson chunkDeleterGson = new GsonBuilder() + .registerTypeAdapter(BlockVector2.class, new BlockVector2Adapter().nullSafe()) + .setPrettyPrinting() + .create(); + + public static ChunkDeletionInfo readInfo(Path chunkFile) throws IOException, JsonSyntaxException { + String json = new String(Files.readAllBytes(chunkFile), StandardCharsets.UTF_8); + return chunkDeleterGson.fromJson(json, ChunkDeletionInfo.class); + } + + public static void writeInfo(ChunkDeletionInfo info, Path chunkFile) throws IOException, JsonIOException { + String json = chunkDeleterGson.toJson(info, new TypeToken() {}.getType()); + try (BufferedWriter writer = Files.newBufferedWriter(chunkFile)) { + writer.write(json); + } + } + + public static void runFromFile(Path chunkFile, boolean deleteOnSuccess) { + ChunkDeleter chunkDeleter; + try { + chunkDeleter = createFromFile(chunkFile); + } catch (JsonSyntaxException | IOException e) { + LOGGER.error("Could not parse chunk deletion file. Invalid file?", e); + return; + } + LOGGER.info("Found chunk deletions. Proceeding with deletion..."); + long start = System.currentTimeMillis(); + if (chunkDeleter.runDeleter()) { + LOGGER.info("Successfully deleted {} matching chunks (out of {}, taking {} ms).", + chunkDeleter.getDeletedChunkCount(), chunkDeleter.getDeletionsRequested(), + System.currentTimeMillis() - start); + if (deleteOnSuccess) { + boolean deletedFile = false; + try { + deletedFile = Files.deleteIfExists(chunkFile); + } catch (IOException ignored) { + } + if (!deletedFile) { + LOGGER.warn("Chunk deletion file could not be cleaned up. This may have unintended consequences" + + " on next startup, or if /delchunks is used again."); + } + } + } else { + LOGGER.error("Error occurred while deleting chunks. " + + "If world errors occur, stop the server and restore the *.bak backup files."); + } + } + + private ChunkDeleter(ChunkDeletionInfo chunkDeletionInfo) { + this.chunkDeletionInfo = chunkDeletionInfo; + } + + private static ChunkDeleter createFromFile(Path chunkFile) throws IOException { + ChunkDeletionInfo info = readInfo(chunkFile); + if (info == null) { + throw new IOException("Read null json. Empty file?"); + } + return new ChunkDeleter(info); + } + + private final ChunkDeletionInfo chunkDeletionInfo; + private final Set backedUpRegions = new HashSet<>(); + private boolean shouldPreload; + private int debugRate = 100; + private int totalChunksDeleted = 0; + private int deletionsRequested = 0; + + private boolean runDeleter() { + return chunkDeletionInfo.batches.stream().allMatch(this::runBatch); + } + + private boolean runBatch(ChunkDeletionInfo.ChunkBatch chunkBatch) { + int chunkCount = chunkBatch.getChunkCount(); + LOGGER.debug("Processing deletion batch with {} chunks.", chunkCount); + final Map> regionToChunkList = groupChunks(chunkBatch); + BiPredicate predicate = createPredicates(chunkBatch.deletionPredicates); + shouldPreload = chunkBatch.chunks == null; + deletionsRequested += chunkCount; + debugRate = chunkCount / 10; + + return regionToChunkList.entrySet().stream().allMatch(entry -> { + Path regionPath = entry.getKey(); + if (!Files.exists(regionPath)) { + return true; + } + if (chunkBatch.backup && !backedUpRegions.contains(regionPath)) { + try { + backupRegion(regionPath); + } catch (IOException e) { + LOGGER.warn("Error backing up region file: " + regionPath + ". Aborting the process.", e); + return false; + } + } + return deleteChunks(regionPath, entry.getValue(), predicate); + }); + } + + private Map> groupChunks(ChunkDeletionInfo.ChunkBatch chunkBatch) { + Path worldPath = Paths.get(chunkBatch.worldPath); + if (chunkBatch.chunks != null) { + return chunkBatch.chunks.stream() + .collect(Collectors.groupingBy(RegionFilePos::new)) + .entrySet().stream().collect(Collectors.toMap( + e -> worldPath.resolve("region").resolve(e.getKey().getFileName()), + e -> e.getValue().stream().sorted(chunkSorter))); + } else { + final BlockVector2 minChunk = chunkBatch.minChunk; + final BlockVector2 maxChunk = chunkBatch.maxChunk; + final RegionFilePos minRegion = new RegionFilePos(minChunk); + final RegionFilePos maxRegion = new RegionFilePos(maxChunk); + Map> groupedChunks = new HashMap<>(); + for (int regX = minRegion.getX(); regX <= maxRegion.getX(); regX++) { + for (int regZ = minRegion.getZ(); regZ <= maxRegion.getZ(); regZ++) { + final Path regionPath = worldPath.resolve("region").resolve(new RegionFilePos(regX, regZ).getFileName()); + if (!Files.exists(regionPath)) { + continue; + } + int startX = regX << 5; + int endX = (regX << 5) + 31; + int startZ = regZ << 5; + int endZ = (regZ << 5) + 31; + + int minX = Math.max(Math.min(startX, endX), minChunk.getBlockX()); + int minZ = Math.max(Math.min(startZ, endZ), minChunk.getBlockZ()); + int maxX = Math.min(Math.max(startX, endX), maxChunk.getBlockX()); + int maxZ = Math.min(Math.max(startZ, endZ), maxChunk.getBlockZ()); + Stream stream = Stream.iterate(BlockVector2.at(minX, minZ), + bv2 -> { + int nextX = bv2.getBlockX(); + int nextZ = bv2.getBlockZ(); + if (++nextX > maxX) { + nextX = minX; + if (++nextZ > maxZ) { + return null; + } + } + return BlockVector2.at(nextX, nextZ); + }); + groupedChunks.put(regionPath, stream); + } + } + return groupedChunks; + } + } + + private BiPredicate createPredicates(List deletionPredicates) { + if (deletionPredicates == null) { + return (r, p) -> true; + } + return deletionPredicates.stream() + .map(this::createPredicate) + .reduce(BiPredicate::and) + .orElse((r, p) -> true); + } + + private BiPredicate createPredicate(ChunkDeletionInfo.DeletionPredicate deletionPredicate) { + if ("modification".equals(deletionPredicate.property)) { + int time; + try { + time = Integer.parseInt(deletionPredicate.value); + } catch (NumberFormatException e) { + throw new IllegalStateException("Modification time predicate specified invalid time: " + deletionPredicate.value); + } + switch (deletionPredicate.comparison) { + case "<": + return (r, p) -> { + try { + return r.getModificationTime(p) < time; + } catch (IOException e) { + return false; + } + }; + case ">": + return (r, p) -> { + try { + return r.getModificationTime(p) > time; + } catch (IOException e) { + return false; + } + }; + default: + throw new IllegalStateException("Unexpected comparison value: " + deletionPredicate.comparison); + } + } + throw new IllegalStateException("Unexpected property value: " + deletionPredicate.property); + } + + private void backupRegion(Path regionFile) throws IOException { + Path backupFile = regionFile.resolveSibling(regionFile.getFileName() + ".bak"); + Files.copy(regionFile, backupFile, StandardCopyOption.REPLACE_EXISTING); + backedUpRegions.add(backupFile); + } + + private boolean deleteChunks(Path regionFile, Stream chunks, + BiPredicate deletionPredicate) { + try (RegionAccess region = new RegionAccess(regionFile, shouldPreload)) { + for (Iterator iterator = chunks.iterator(); iterator.hasNext();) { + BlockVector2 chunk = iterator.next(); + if (chunk == null) { + break; + } + if (deletionPredicate.test(region, chunk)) { + region.deleteChunk(chunk); + totalChunksDeleted++; + if (debugRate != 0 && totalChunksDeleted % debugRate == 0) { + LOGGER.debug("Deleted {} chunks so far.", totalChunksDeleted); + } + } else { + LOGGER.debug("Chunk did not match predicates: " + chunk); + } + } + return true; + } catch (IOException e) { + LOGGER.warn("Error deleting chunks from region: " + regionFile + ". Aborting the process.", e); + return false; + } + } + + public int getDeletedChunkCount() { + return totalChunksDeleted; + } + + public int getDeletionsRequested() { + return deletionsRequested; + } + + private static class BlockVector2Adapter extends TypeAdapter { + @Override + public void write(JsonWriter out, BlockVector2 value) throws IOException { + out.beginArray(); + out.value(value.getBlockX()); + out.value(value.getBlockZ()); + out.endArray(); + } + + @Override + public BlockVector2 read(JsonReader in) throws IOException { + in.beginArray(); + int x = in.nextInt(); + int z = in.nextInt(); + in.endArray(); + return BlockVector2.at(x, z); + } + } + + private static class RegionFilePos { + private final int x; + private final int z; + + RegionFilePos(BlockVector2 chunk) { + this.x = chunk.getBlockX() >> 5; + this.z = chunk.getBlockZ() >> 5; + } + + RegionFilePos(int regX, int regZ) { + this.x = regX; + this.z = regZ; + } + + public int getX() { + return x; + } + + public int getZ() { + return z; + } + + public String getFileName() { + return "r." + x + "." + z + ".mca"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + RegionFilePos that = (RegionFilePos) o; + + if (x != that.x) { + return false; + } + return z == that.z; + + } + + @Override + public int hashCode() { + int result = x; + result = 31 * result + z; + return result; + } + + @Override + public String toString() { + return "(" + x + ", " + z + ")"; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java b/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java new file mode 100644 index 0000000..adf001f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java @@ -0,0 +1,56 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.anvil; + +import com.sk89q.worldedit.math.BlockVector2; + +import java.util.List; + +/** + * Internal class. Subject to changes. + */ +public class ChunkDeletionInfo { + + public List batches; + + public static class ChunkBatch { + public String worldPath; + public boolean backup; + public List deletionPredicates; + // specify either list of chunks, or min-max + public List chunks; + public BlockVector2 minChunk; + public BlockVector2 maxChunk; + + public int getChunkCount() { + if (chunks != null) { + return chunks.size(); + } + final BlockVector2 dist = maxChunk.subtract(minChunk).add(1, 1); + return dist.getBlockX() * dist.getBlockZ(); + } + } + + public static class DeletionPredicate { + public String property; + public String comparison; + public String value; + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java b/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java new file mode 100644 index 0000000..4a7e7d9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java @@ -0,0 +1,101 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.anvil; + +import com.sk89q.worldedit.math.BlockVector2; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.file.Path; + +/** + * Internal class. Subject to changes. + */ +class RegionAccess implements AutoCloseable { + + private final RandomAccessFile raf; + private int[] offsets; + private int[] timestamps; + + RegionAccess(Path file) throws IOException { + this(file, false); + } + + RegionAccess(Path file, boolean preload) throws IOException { + raf = new RandomAccessFile(file.toFile(), "rw"); + if (preload) { + readHeaders(); + } + } + + private void readHeaders() throws IOException { + offsets = new int[1024]; + timestamps = new int[1024]; + for (int idx = 0; idx < 1024; ++idx) { + offsets[idx] = raf.readInt(); + } + for (int idx = 0; idx < 1024; ++idx) { + timestamps[idx] = raf.readInt(); + } + } + + private static int indexChunk(BlockVector2 pos) { + int x = pos.getBlockX() & 31; + int z = pos.getBlockZ() & 31; + return x + z * 32; + } + + int getModificationTime(BlockVector2 pos) throws IOException { + int idx = indexChunk(pos); + if (timestamps != null) { + return timestamps[idx]; + } + raf.seek(idx * 4L + 4096); + return raf.readInt(); + } + + int getChunkSize(BlockVector2 pos) throws IOException { + int idx = indexChunk(pos); + if (offsets != null) { + return offsets[idx] & 0xFF; + } + raf.seek(idx * 4L); + // 3 bytes for offset + raf.read(); + raf.read(); + raf.read(); + // one byte for size - note, yes, could do raf.readInt() & 0xFF but that does extra checks + return raf.read(); + } + + void deleteChunk(BlockVector2 pos) throws IOException { + int idx = indexChunk(pos); + raf.seek(idx * 4L); + raf.writeInt(0); + if (offsets != null) { + offsets[idx] = 0; + } + } + + @Override + public void close() throws IOException { + raf.close(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java b/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java new file mode 100644 index 0000000..4fedf62 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java @@ -0,0 +1,111 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.block; + +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.registry.BlockRegistry; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +import javax.annotation.Nullable; +import java.util.BitSet; +import java.util.OptionalInt; + +import static com.google.common.base.Preconditions.checkState; + +public final class BlockStateIdAccess { + + private static final int INVALID_ID = -1; + private static final int EXPECTED_BLOCK_COUNT = 2 << 14; + private static final Int2ObjectOpenHashMap TO_STATE = + new Int2ObjectOpenHashMap<>(EXPECTED_BLOCK_COUNT); + + static { + TO_STATE.defaultReturnValue(null); + } + + public interface BlockStateInternalId { + int getInternalId(BlockState blockState); + + void setInternalId(BlockState blockState, int internalId); + } + + private static BlockStateInternalId blockStateInternalId; + + public static void setBlockStateInternalId(BlockStateInternalId blockStateInternalId) { + BlockStateIdAccess.blockStateInternalId = blockStateInternalId; + } + + /** + * An invalid internal ID, for verification purposes. + * @return an internal ID which is never valid + */ + public static int invalidId() { + return INVALID_ID; + } + + public static boolean isValidInternalId(int internalId) { + return internalId != INVALID_ID; + } + + public static int getBlockStateId(BlockState holder) { + return blockStateInternalId.getInternalId(holder); + } + + public static @Nullable BlockState getBlockStateById(int id) { + return TO_STATE.get(id); + } + + /** + * For platforms that don't have an internal ID system, + * {@link BlockRegistry#getInternalBlockStateId(BlockState)} will return + * {@link OptionalInt#empty()}. In those cases, we will use our own ID system, + * since it's useful for other entries as well. + * + * @return an unused ID in WorldEdit's ID tracker + */ + private static int provideUnusedWorldEditId() { + return usedIds.nextClearBit(0); + } + + private static final BitSet usedIds = new BitSet(); + + public static void register(BlockState blockState, int id) { + int i = isValidInternalId(id) ? id : provideUnusedWorldEditId(); + BlockState existing = getBlockStateById(id); + checkState(existing == null || existing == blockState, + "BlockState %s is using the same block ID (%s) as BlockState %s", + blockState, i, existing); + blockStateInternalId.setInternalId(blockState, i); + TO_STATE.put(i, blockState); + usedIds.set(i); + } + + public static void clear() { + for (BlockState value : TO_STATE.values()) { + blockStateInternalId.setInternalId(value, invalidId()); + } + TO_STATE.clear(); + usedIds.clear(); + } + + private BlockStateIdAccess() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/command/ActorAuthorizer.java b/src/main/java/com/sk89q/worldedit/internal/command/ActorAuthorizer.java new file mode 100644 index 0000000..b161fb5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/command/ActorAuthorizer.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.command; + +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.auth.Authorizer; + +/** + * Implementation of an authorizer that uses {@link Actor#hasPermission(String)}. + */ +public class ActorAuthorizer implements Authorizer { + + @Override + public boolean testPermission(CommandLocals locals, String permission) { + Actor sender = locals.get(Actor.class); + if (sender == null) { + throw new RuntimeException("Uh oh! No 'Actor' specified so that we can check permissions"); + } else { + return sender.hasPermission(permission); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java b/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java new file mode 100644 index 0000000..092844b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java @@ -0,0 +1,131 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.command; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.sk89q.worldedit.internal.util.Substring; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CommandArgParser { + + public static CommandArgParser forArgString(String argString) { + return new CommandArgParser(spaceSplit(argString)); + } + + public static ImmutableList spaceSplit(String string) { + ImmutableList.Builder result = ImmutableList.builder(); + int index = 0; + for (String part : Splitter.on(' ').split(string)) { + result.add(Substring.from(string, index, index + part.length())); + index += part.length() + 1; + } + return result.build(); + } + + private enum State { + NORMAL, + QUOTE + } + + private final Stream.Builder args = Stream.builder(); + private final List input; + private final List currentArg = new ArrayList<>(); + private int index = 0; + private State state = State.NORMAL; + + public CommandArgParser(List input) { + this.input = input; + } + + public Stream parseArgs() { + for (; index < input.size(); index++) { + Substring nextPart = input.get(index); + switch (state) { + case NORMAL: + handleNormal(nextPart); + break; + case QUOTE: + handleQuote(nextPart); + break; + default: + break; + } + } + if (currentArg.size() > 0) { + finishArg(); // force finish "hanging" args + } + return args.build(); + } + + private void handleNormal(Substring part) { + final String strPart = part.getSubstring(); + if (strPart.startsWith("\"")) { + if (strPart.endsWith("\"") && strPart.length() > 1) { + currentArg.add(Substring.wrap( + strPart.substring(1, strPart.length() - 1), + part.getStart() + 1, part.getEnd() - 1 + )); + finishArg(); + } else { + state = State.QUOTE; + currentArg.add(Substring.wrap( + strPart.substring(1), + part.getStart() + 1, part.getEnd() + )); + } + } else { + currentArg.add(part); + finishArg(); + } + } + + private void handleQuote(Substring part) { + if (part.getSubstring().endsWith("\"")) { + state = State.NORMAL; + currentArg.add(Substring.wrap( + part.getSubstring().substring(0, part.getSubstring().length() - 1), + part.getStart(), part.getEnd() - 1 + )); + finishArg(); + } else { + currentArg.add(part); + } + } + + private void finishArg() { + // Merge the arguments into a single, space-joined, string + // Keep the original start + end points. + int start = currentArg.get(0).getStart(); + int end = Iterables.getLast(currentArg).getEnd(); + args.add(Substring.wrap(currentArg.stream() + .map(Substring::getSubstring) + .collect(Collectors.joining(" ")), + start, end + )); + currentArg.clear(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java b/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java new file mode 100644 index 0000000..b988733 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java @@ -0,0 +1,155 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.command; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.world.World; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.gen.CommandCallListener; +import org.enginehub.piston.inject.Key; + +import java.lang.reflect.Method; +import java.util.Optional; +import java.util.logging.Handler; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Logs called commands to a logger. + */ +public class CommandLoggingHandler implements CommandCallListener, AutoCloseable { + + private final WorldEdit worldEdit; + private final Logger logger; + + /** + * Create a new instance. + * + * @param worldEdit an instance of WorldEdit + * @param logger the logger to send messages to + */ + public CommandLoggingHandler(WorldEdit worldEdit, Logger logger) { + checkNotNull(worldEdit); + checkNotNull(logger); + this.worldEdit = worldEdit; + this.logger = logger; + } + + @Override + public void beforeCall(Method method, CommandParameters parameters) { + Logging loggingAnnotation = method.getAnnotation(Logging.class); + Logging.LogMode logMode; + StringBuilder builder = new StringBuilder(); + + if (loggingAnnotation == null) { + logMode = null; + } else { + logMode = loggingAnnotation.value(); + } + + Optional actorOpt = parameters.injectedValue(Key.of(Actor.class)); + + if (!actorOpt.isPresent()) { + return; + } + Actor actor = actorOpt.get(); + + World world; + try { + Optional worldOpt = parameters.injectedValue(Key.of(World.class)); + if (!worldOpt.isPresent()) { + return; + } + world = worldOpt.get(); + } catch (CommandException ex) { + return; + } + + builder.append("WorldEdit: ").append(actor.getName()); + builder.append(" (in \"").append(world.getName()).append("\")"); + + builder.append(": ").append(parameters.getMetadata().getCalledName()); + + builder.append(": ") + .append(Stream.concat( + Stream.of(parameters.getMetadata().getCalledName()), + parameters.getMetadata().getArguments().stream() + ).collect(Collectors.joining(" "))); + + if (logMode != null && actor instanceof Player) { + Player player = (Player) actor; + Vector3 position = player.getLocation().toVector(); + LocalSession session = worldEdit.getSessionManager().get(actor); + + switch (logMode) { + case PLACEMENT: + try { + position = session.getPlacementPosition(actor).toVector3(); + } catch (IncompleteRegionException e) { + break; + } + /* FALL-THROUGH */ + + case POSITION: + builder.append(" - Position: ").append(position); + break; + + case ALL: + builder.append(" - Position: ").append(position); + /* FALL-THROUGH */ + + case ORIENTATION_REGION: + builder.append(" - Orientation: ").append(player.getCardinalDirection().name()); + /* FALL-THROUGH */ + + case REGION: + try { + builder.append(" - Region: ") + .append(session.getSelection(world)); + } catch (IncompleteRegionException e) { + break; + } + break; + default: + break; + } + } + + logger.info(builder.toString()); + } + + @Override + public void close() { + for (Handler h : logger.getHandlers()) { + h.close(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java b/src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java new file mode 100644 index 0000000..a935bed --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java @@ -0,0 +1,51 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.command; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.gen.CommandCallListener; +import org.enginehub.piston.gen.CommandRegistration; + +import java.util.List; + +public class CommandRegistrationHandler { + + private static final CommandPermissionsConditionGenerator PERM_GEN = new CommandPermissionsConditionGenerator(); + + private final List callListeners; + + public CommandRegistrationHandler(List callListeners) { + this.callListeners = ImmutableList.copyOf(callListeners); + } + + public void register(CommandManager manager, CommandRegistration registration, CI instance) { + registration.containerInstance(instance) + .commandManager(manager) + .listeners(callListeners); + if (registration instanceof CommandPermissionsConditionGenerator.Registration) { + ((CommandPermissionsConditionGenerator.Registration) registration).commandPermissionsConditionGenerator( + PERM_GEN + ); + } + registration.build(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java b/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java new file mode 100644 index 0000000..ab0195e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java @@ -0,0 +1,296 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.command; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.PlatformCommandManager; +import com.sk89q.worldedit.internal.util.Substring; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.format.TextColor; +import net.kyori.text.format.TextDecoration; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.NoInputCommandParameters; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.part.SubCommandPart; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkState; +import static java.util.stream.Collectors.toList; + +public class CommandUtil { + + private static final Component DEPRECATION_MARKER = TextComponent.of("This command is deprecated."); + + private static Component makeDeprecatedFooter(String reason, Component replacement) { + return TextComponent.builder() + .append(DEPRECATION_MARKER) + .append(" " + reason + ".") + .append(TextComponent.newline()) + .append(replacement.color(TextColor.GOLD)) + .build(); + } + + public interface NewCommandGenerator { + + String newCommand(Command oldCommand, CommandParameters oldParameters); + + } + + public interface ReplacementMessageGenerator { + + /** + * Generate text that says "Please use [cmd] instead." and allows clicking to dump + * the command to the text box. + */ + static ReplacementMessageGenerator forNewCommand(NewCommandGenerator generator) { + return (oldCommand, oldParameters) -> { + String suggestedCommand = generator.newCommand(oldCommand, oldParameters); + return createNewCommandReplacementText(suggestedCommand); + }; + } + + Component getReplacement(Command oldCommand, CommandParameters oldParameters); + + } + + public static Component createNewCommandReplacementText(String suggestedCommand) { + return TextComponent.builder("Please use ", TextColor.GOLD) + .append(TextComponent.of(suggestedCommand) + .decoration(TextDecoration.UNDERLINED, true) + .clickEvent(ClickEvent.suggestCommand(suggestedCommand))) + .append(" instead.") + .build(); + } + + public static Command deprecate(Command command, String reason, + ReplacementMessageGenerator replacementMessageGenerator) { + Component deprecatedWarning = makeDeprecatedFooter( + reason, + replacementMessageGenerator.getReplacement( + command, + NoInputCommandParameters.builder().build() + ) + ); + return command.toBuilder() + .action(parameters -> + deprecatedCommandWarning(parameters, command, reason, replacementMessageGenerator)) + .footer(command.getFooter() + .map(existingFooter -> existingFooter + .append(TextComponent.newline()) + .append(deprecatedWarning)) + .orElse(deprecatedWarning)) + .build(); + } + + public static Optional footerWithoutDeprecation(Command command) { + return command.getFooter() + .filter(footer -> anyComponent(footer, Predicate.isEqual(DEPRECATION_MARKER))) + .map(footer -> Optional.of( + replaceDeprecation(footer) + )) + .orElseGet(command::getFooter); + } + + public static Optional deprecationWarning(Command command) { + return command.getFooter() + .map(CommandUtil::extractDeprecation) + .orElseGet(command::getFooter); + } + + public static boolean isDeprecated(Command command) { + return command.getFooter() + .filter(footer -> anyComponent(footer, Predicate.isEqual(DEPRECATION_MARKER))) + .isPresent(); + } + + private static boolean anyComponent(Component component, Predicate test) { + return test.test(component) || component.children().stream() + .anyMatch(x -> anyComponent(x, test)); + } + + private static Component replaceDeprecation(Component component) { + if (component.children().stream().anyMatch(Predicate.isEqual(DEPRECATION_MARKER))) { + return TextComponent.empty(); + } + return component.children( + component.children().stream() + .map(CommandUtil::replaceDeprecation) + .collect(toList()) + ); + } + + private static Optional extractDeprecation(Component component) { + if (component.children().stream().anyMatch(Predicate.isEqual(DEPRECATION_MARKER))) { + return Optional.of(component); + } + return component.children().stream() + .map(CommandUtil::extractDeprecation) + .filter(Optional::isPresent) + .map(Optional::get) + .findAny(); + } + + private static int deprecatedCommandWarning( + CommandParameters parameters, + Command command, + String reason, + ReplacementMessageGenerator generator + ) throws Exception { + parameters.injectedValue(Key.of(Actor.class)) + .ifPresent(actor -> + sendDeprecationMessage(parameters, command, reason, generator, actor) + ); + return command.getAction().run(parameters); + } + + private static void sendDeprecationMessage( + CommandParameters parameters, + Command command, + String reason, + ReplacementMessageGenerator generator, + Actor actor + ) { + Component replacement = generator.getReplacement(command, parameters); + actor.print( + TextComponent.builder(reason + ". ", TextColor.GOLD) + .append(replacement) + .build() + ); + } + + public static Map getSubCommands(Command currentCommand) { + return currentCommand.getParts().stream() + .filter(p -> p instanceof SubCommandPart) + .flatMap(p -> ((SubCommandPart) p).getCommands().stream()) + .collect(Collectors.toMap(Command::getName, Function.identity())); + } + + private static String clean(String input) { + return PlatformCommandManager.COMMAND_CLEAN_PATTERN.matcher(input).replaceAll(""); + } + + private static final Comparator BY_CLEAN_NAME = + Comparator.comparing(c -> clean(c.getName())); + + public static Comparator byCleanName() { + return BY_CLEAN_NAME; + } + + /** + * Fix {@code suggestions} to replace the last space-separated word in {@code arguments}. + */ + public static List fixSuggestions(String arguments, List suggestions) { + Substring lastArg = Iterables.getLast( + CommandArgParser.spaceSplit(arguments) + ); + return suggestions.stream() + // Re-map suggestions to only operate on the last non-quoted word + .map(suggestion -> onlyOnLastQuotedWord(lastArg, suggestion)) + .map(suggestion -> suggestLast(lastArg, suggestion)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(toList()); + } + + private static Substring onlyOnLastQuotedWord(Substring lastArg, Substring suggestion) { + if (suggestion.getSubstring().startsWith(lastArg.getSubstring())) { + // This is already fine. + return suggestion; + } + String substr = suggestion.getSubstring(); + int sp = substr.lastIndexOf(' '); + if (sp < 0) { + return suggestion; + } + return Substring.wrap(substr.substring(sp + 1), suggestion.getStart() + sp + 1, suggestion.getEnd()); + } + + /** + * Given the last word of a command, mutate the suggestion to replace the last word, if + * possible. + */ + private static Optional suggestLast(Substring last, Substring suggestion) { + if (suggestion.getStart() == last.getEnd() && !last.getSubstring().equals("\"")) { + // this suggestion is for the next argument. + if (last.getSubstring().isEmpty()) { + return Optional.of(suggestion.getSubstring()); + } + return Optional.of(last.getSubstring() + " " + suggestion.getSubstring()); + } + StringBuilder builder = new StringBuilder(last.getSubstring()); + int start = suggestion.getStart() - last.getStart(); + int end = suggestion.getEnd() - last.getStart(); + if (start < 0) { + // Quoted suggestion, can't complete it here. + return Optional.empty(); + } + checkState(end <= builder.length(), + "Suggestion ends too late, last=%s, suggestion=", last, suggestion); + builder.replace(start, end, suggestion.getSubstring()); + return Optional.of(builder.toString()); + } + + /** + * Require {@code condition} to be {@code true}, otherwise throw a {@link CommandException} + * with the given message. + * + * @param condition the condition to check + * @param message the message for failure + */ + public static void checkCommandArgument(boolean condition, String message) { + checkCommandArgument(condition, TextComponent.of(message)); + } + + /** + * Require {@code condition} to be {@code true}, otherwise throw a {@link CommandException} + * with the given message. + * + * @param condition the condition to check + * @param message the message for failure + */ + public static void checkCommandArgument(boolean condition, Component message) { + if (!condition) { + throw new CommandException(message, ImmutableList.of()); + } + } + + public static T requireIV(Key type, String name, InjectedValueAccess injectedValueAccess) { + return injectedValueAccess.injectedValue(type).orElseThrow(() -> + new IllegalStateException("No injected value for " + name + " (type " + type + ")") + ); + } + + private CommandUtil() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverter.java b/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverter.java new file mode 100644 index 0000000..f2eb44a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverter.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.command.exception; + + +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.CommandExecutionException; + +/** + * Used to convert a recognized {@link Throwable} into an appropriate + * {@link CommandException}. + * + *

Methods may throw relevant exceptions that are not caught by the command manager, + * but translate into reasonable exceptions for an application. However, unknown exceptions are + * normally simply wrapped in a {@link CommandExecutionException} and bubbled up. Only + * normal {@link CommandException}s will be printed correctly, so a converter translates + * one of these unknown exceptions into an appropriate {@link CommandException}.

+ * + *

This also allows the code calling the command to not need be aware of these + * application-specific exceptions, as they will all be converted to + * {@link CommandException}s that are handled normally.

+ */ +public interface ExceptionConverter { + + /** + * Attempt to convert the given throwable into a {@link CommandException}. + * + *

If the exception is not recognized, then nothing should be thrown.

+ * + * @param t the throwable + * @throws CommandException a command exception + */ + void convert(Throwable t) throws CommandException; + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java b/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java new file mode 100644 index 0000000..dd48e0f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java @@ -0,0 +1,114 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.command.exception; + +import com.google.common.collect.ImmutableList; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.CommandExecutionException; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * An implementation of an {@link ExceptionConverter} that automatically calls + * the correct method defined on this object. + * + *

Only public methods will be used. Methods will be called in order of decreasing + * levels of inheritance (between classes where one inherits the other). For two + * different inheritance branches, the order between them is undefined.

+ */ +public abstract class ExceptionConverterHelper implements ExceptionConverter { + + private final List handlers; + + @SuppressWarnings("unchecked") + public ExceptionConverterHelper() { + List handlers = new ArrayList<>(); + + for (Method method : this.getClass().getMethods()) { + if (method.getAnnotation(ExceptionMatch.class) == null) { + continue; + } + + Class[] parameters = method.getParameterTypes(); + if (parameters.length == 1) { + Class cls = parameters[0]; + if (Throwable.class.isAssignableFrom(cls)) { + handlers.add(new ExceptionHandler( + (Class) cls, method)); + } + } + } + + Collections.sort(handlers); + + this.handlers = handlers; + } + + @SuppressWarnings("deprecation") + @Override + public void convert(Throwable t) throws CommandException { + Class throwableClass = t.getClass(); + for (ExceptionHandler handler : handlers) { + if (handler.cls.isAssignableFrom(throwableClass)) { + try { + handler.method.invoke(this, t); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof CommandException) { + throw (CommandException) e.getCause(); + } + if (e.getCause() instanceof com.sk89q.minecraft.util.commands.CommandException) { + throw new CommandExecutionException(e.getCause(), ImmutableList.of()); + } + throw new CommandExecutionException(e, ImmutableList.of()); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new CommandExecutionException(e, ImmutableList.of()); + } + } + } + } + + private static class ExceptionHandler implements Comparable { + final Class cls; + final Method method; + + private ExceptionHandler(Class cls, Method method) { + this.cls = cls; + this.method = method; + } + + @Override + public int compareTo(ExceptionHandler o) { + if (cls.equals(o.cls)) { + return 0; + } else if (cls.isAssignableFrom(o.cls)) { + return 1; + } else if (o.cls.isAssignableFrom(cls)) { + return -1; + } else { + return cls.getCanonicalName().compareTo(o.cls.getCanonicalName()); + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionMatch.java b/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionMatch.java new file mode 100644 index 0000000..3befc56 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionMatch.java @@ -0,0 +1,34 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.command.exception; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Denotes a match of an exception. + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExceptionMatch { + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java b/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java new file mode 100644 index 0000000..6bee624 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java @@ -0,0 +1,188 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.command.exception; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.command.InsufficientArgumentsException; +import com.sk89q.worldedit.command.tool.InvalidToolBindException; +import com.sk89q.worldedit.extension.input.DisallowedUsageException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.regions.RegionOperationException; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException; +import com.sk89q.worldedit.util.io.file.FilenameResolutionException; +import com.sk89q.worldedit.util.io.file.InvalidFilenameException; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.UsageException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * converts WorldEdit exceptions and converts them into {@link CommandException}s. + */ +public class WorldEditExceptionConverter extends ExceptionConverterHelper { + + private static final Pattern numberFormat = Pattern.compile("^For input string: \"(.*)\"$"); + private final WorldEdit worldEdit; + + public WorldEditExceptionConverter(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + + private CommandException newCommandException(String message, Throwable cause) { + return newCommandException(TextComponent.of(String.valueOf(message)), cause); + } + + private CommandException newCommandException(Component message, Throwable cause) { + return new CommandException(message, cause, ImmutableList.of()); + } + + @ExceptionMatch + public void convert(NumberFormatException e) throws CommandException { + final Matcher matcher = numberFormat.matcher(e.getMessage()); + + if (matcher.matches()) { + throw newCommandException(TranslatableComponent.of("worldedit.error.invalid-number.matches", TextComponent.of(matcher.group(1))), e); + } else { + throw newCommandException(TranslatableComponent.of("worldedit.error.invalid-number"), e); + } + } + + @ExceptionMatch + public void convert(IncompleteRegionException e) throws CommandException { + throw newCommandException(TranslatableComponent.of("worldedit.error.incomplete-region"), e); + } + + @ExceptionMatch + public void convert(MissingWorldException e) throws CommandException { + throw newCommandException(e.getRichMessage(), e); + } + + @ExceptionMatch + public void convert(NoMatchException e) throws CommandException { + throw newCommandException(e.getRichMessage(), e); + } + + @Deprecated + @ExceptionMatch + public void convert(InvalidItemException e) throws CommandException { + throw newCommandException(e.getRichMessage(), e); + } + + @ExceptionMatch + public void convert(DisallowedUsageException e) throws CommandException { + throw newCommandException(e.getRichMessage(), e); + } + + @ExceptionMatch + public void convert(MaxChangedBlocksException e) throws CommandException { + throw newCommandException(TranslatableComponent.of("worldedit.error.max-changes", TextComponent.of(e.getBlockLimit())), e); + } + + @ExceptionMatch + public void convert(MaxBrushRadiusException e) throws CommandException { + throw newCommandException( + TranslatableComponent.of("worldedit.error.max-brush-radius", TextComponent.of(worldEdit.getConfiguration().maxBrushRadius)), + e + ); + } + + @ExceptionMatch + public void convert(MaxRadiusException e) throws CommandException { + throw newCommandException( + TranslatableComponent.of("worldedit.error.max-radius", TextComponent.of(worldEdit.getConfiguration().maxRadius)), + e + ); + } + + @ExceptionMatch + public void convert(UnknownDirectionException e) throws CommandException { + throw newCommandException(e.getRichMessage(), e); + } + + @ExceptionMatch + public void convert(InsufficientArgumentsException e) throws CommandException { + throw newCommandException(e.getRichMessage(), e); + } + + @ExceptionMatch + public void convert(RegionOperationException e) throws CommandException { + throw newCommandException(e.getRichMessage(), e); + } + + @ExceptionMatch + public void convert(ExpressionException e) throws CommandException { + throw newCommandException(e.getMessage(), e); + } + + @ExceptionMatch + public void convert(EmptyClipboardException e) throws CommandException { + throw newCommandException(TranslatableComponent.of("worldedit.error.empty-clipboard"), e); + } + + @ExceptionMatch + public void convert(InvalidFilenameException e) throws CommandException { + throw newCommandException( + TranslatableComponent.of("worldedit.error.invalid-filename", TextComponent.of(e.getFilename()), e.getRichMessage()), + e + ); + } + + @ExceptionMatch + public void convert(FilenameResolutionException e) throws CommandException { + throw newCommandException( + TranslatableComponent.of("worldedit.error.file-resolution", TextComponent.of(e.getFilename()), e.getRichMessage()), + e + ); + } + + @ExceptionMatch + public void convert(InvalidToolBindException e) throws CommandException { + throw newCommandException( + TranslatableComponent.of("worldedit.tool.error.cannot-bind", e.getItemType().getRichName(), e.getRichMessage()), + e + ); + } + + @ExceptionMatch + public void convert(FileSelectionAbortedException e) throws CommandException { + throw newCommandException(TranslatableComponent.of("worldedit.error.file-aborted"), e); + } + + @ExceptionMatch + public void convert(WorldEditException e) throws CommandException { + throw newCommandException(e.getRichMessage(), e); + } + + // Prevent investigation into UsageExceptions + @ExceptionMatch + public void convert(UsageException e) throws CommandException { + throw e; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/cui/CUIEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/CUIEvent.java new file mode 100644 index 0000000..f60328b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/cui/CUIEvent.java @@ -0,0 +1,27 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.cui; + +public interface CUIEvent { + + String getTypeId(); + + String[] getParameters(); +} diff --git a/src/main/java/com/sk89q/worldedit/internal/cui/CUIRegion.java b/src/main/java/com/sk89q/worldedit/internal/cui/CUIRegion.java new file mode 100644 index 0000000..81360cd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/cui/CUIRegion.java @@ -0,0 +1,66 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.cui; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.platform.Actor; + +public interface CUIRegion { + + /** + * Sends CUI events describing the region for + * versions of CUI equal to or greater than the + * value supplied by getProtocolVersion(). + * + */ + void describeCUI(LocalSession session, Actor player); + + /** + * Sends CUI events describing the region for + * versions of CUI smaller than the value + * supplied by getProtocolVersion(). + * + */ + void describeLegacyCUI(LocalSession session, Actor player); + + /** + * Returns the CUI version that is required to send + * up-to-date data. If the CUI version is smaller than + * this value, the legacy methods will be called. + * + * @return the protocol version + */ + int getProtocolVersion(); + + /** + * Returns the type ID to send to CUI in the selection event. + * + * @return the type ID + */ + String getTypeID(); + + /** + * Returns the type ID to send to CUI in the selection + * event if the CUI is in legacy mode. + * + * @return the legacy type ID + */ + String getLegacyTypeID(); +} diff --git a/src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java new file mode 100644 index 0000000..db55c24 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.internal.cui; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector2; + +public class SelectionCylinderEvent implements CUIEvent { + + protected final BlockVector3 pos; + protected final Vector2 radius; + + public SelectionCylinderEvent(BlockVector3 pos, Vector2 radius) { + this.pos = pos; + this.radius = radius; + } + + @Override + public String getTypeId() { + return "cyl"; + } + + @Override + public String[] getParameters() { + return new String[] { + String.valueOf(pos.getBlockX()), + String.valueOf(pos.getBlockY()), + String.valueOf(pos.getBlockZ()), + String.valueOf(radius.getX()), + String.valueOf(radius.getZ()) + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java new file mode 100644 index 0000000..73ee494 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.cui; + +import com.sk89q.worldedit.math.BlockVector3; + +public class SelectionEllipsoidPointEvent implements CUIEvent { + + protected final int id; + protected final BlockVector3 pos; + + public SelectionEllipsoidPointEvent(int id, BlockVector3 pos) { + this.id = id; + this.pos = pos; + } + + @Override + public String getTypeId() { + return "e"; + } + + @Override + public String[] getParameters() { + return new String[] { + String.valueOf(id), + String.valueOf(pos.getBlockX()), + String.valueOf(pos.getBlockY()), + String.valueOf(pos.getBlockZ()) + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/cui/SelectionMinMaxEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionMinMaxEvent.java new file mode 100644 index 0000000..5da6f6b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionMinMaxEvent.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.cui; + +public class SelectionMinMaxEvent implements CUIEvent { + + protected final int min; + protected final int max; + + public SelectionMinMaxEvent(int min, int max) { + this.min = min; + this.max = max; + } + + @Override + public String getTypeId() { + return "mm"; + } + + @Override + public String[] getParameters() { + return new String[] { + String.valueOf(min), + String.valueOf(max), + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java new file mode 100644 index 0000000..36499de --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java @@ -0,0 +1,77 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.cui; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; + +public class SelectionPoint2DEvent implements CUIEvent { + + protected final int id; + protected final int blockX; + protected final int blockZ; + protected final long area; + + @Deprecated + public SelectionPoint2DEvent(int id, BlockVector2 pos, int area) { + this.id = id; + this.blockX = pos.getX(); + this.blockZ = pos.getZ(); + this.area = area; + } + + @Deprecated + public SelectionPoint2DEvent(int id, BlockVector3 pos, int area) { + this.id = id; + this.blockX = pos.getX(); + this.blockZ = pos.getZ(); + this.area = area; + } + + public SelectionPoint2DEvent(int id, BlockVector2 pos, long area) { + this.id = id; + this.blockX = pos.getX(); + this.blockZ = pos.getZ(); + this.area = area; + } + + public SelectionPoint2DEvent(int id, BlockVector3 pos, long area) { + this.id = id; + this.blockX = pos.getX(); + this.blockZ = pos.getZ(); + this.area = area; + } + + @Override + public String getTypeId() { + return "p2"; + } + + @Override + public String[] getParameters() { + return new String[] { + String.valueOf(id), + String.valueOf(blockX), + String.valueOf(blockZ), + String.valueOf(area) + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java new file mode 100644 index 0000000..529f4a8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java @@ -0,0 +1,59 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.cui; + +import com.sk89q.worldedit.math.BlockVector3; + +public class SelectionPointEvent implements CUIEvent { + + protected final int id; + protected final BlockVector3 pos; + protected final long area; + + @Deprecated + public SelectionPointEvent(int id, BlockVector3 pos, int area) { + this.id = id; + this.pos = pos; + this.area = area; + } + + public SelectionPointEvent(int id, BlockVector3 pos, long area) { + this.id = id; + this.pos = pos; + this.area = area; + } + + @Override + public String getTypeId() { + return "p"; + } + + @Override + public String[] getParameters() { + return new String[] { + String.valueOf(id), + String.valueOf(pos.getBlockX()), + String.valueOf(pos.getBlockY()), + String.valueOf(pos.getBlockZ()), + String.valueOf(area) + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPolygonEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPolygonEvent.java new file mode 100644 index 0000000..bb9aac3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPolygonEvent.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.internal.cui; + +public class SelectionPolygonEvent implements CUIEvent { + + protected final int[] vertices; + + public SelectionPolygonEvent(int... vertices) { + this.vertices = vertices; + } + + @Override + public String getTypeId() { + return "poly"; + } + + @Override + public String[] getParameters() { + final String[] ret = new String[vertices.length]; + + int i = 0; + for (int vertex : vertices) { + ret[i++] = String.valueOf(vertex); + } + + return ret; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/cui/SelectionShapeEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionShapeEvent.java new file mode 100644 index 0000000..9ef5218 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionShapeEvent.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.cui; + +public class SelectionShapeEvent implements CUIEvent { + + protected final String shapeName; + + public SelectionShapeEvent(String shapeName) { + this.shapeName = shapeName; + } + + @Override + public String getTypeId() { + return "s"; + } + + @Override + public String[] getParameters() { + return new String[] { shapeName }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java b/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java new file mode 100644 index 0000000..4ed873e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java @@ -0,0 +1,172 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.cui; + +import com.sk89q.jnbt.*; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +/** + * Handles creation of server-side CUI systems. + */ +public class ServerCUIHandler { + + private static final int MAX_DISTANCE = 32; + + private ServerCUIHandler() { + } + + public static int getMaxServerCuiSize() { + int dataVersion = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getDataVersion(); + + // 1.16 increased maxSize to 48. + return dataVersion >= 2566 ? 48 : 32; + } + + /** + * Creates a structure block that shows the region. + * + *

+ * Null symbolises removal of the CUI. + *

+ * + * @param player The player to create the structure block for. + * @return The structure block, or null + */ + @Nullable + public static BaseBlock createStructureBlock(Player player) { + LocalSession session = WorldEdit.getInstance().getSessionManager().get(player); + RegionSelector regionSelector = session.getRegionSelector(player.getWorld()); + + int posX; + int posY; + int posZ; + int width; + int height; + int length; + + if (regionSelector instanceof CuboidRegionSelector) { + if (regionSelector.isDefined()) { + try { + CuboidRegion region = ((CuboidRegionSelector) regionSelector).getRegion(); + + posX = region.getMinimumPoint().getBlockX(); + posY = region.getMinimumPoint().getBlockY(); + posZ = region.getMinimumPoint().getBlockZ(); + + width = region.getWidth(); + height = region.getHeight(); + length = region.getLength(); + } catch (IncompleteRegionException e) { + // This will never happen. + e.printStackTrace(); + return null; + } + } else { + CuboidRegion region = ((CuboidRegionSelector) regionSelector).getIncompleteRegion(); + BlockVector3 point; + if (region.getPos1() != null) { + point = region.getPos1(); + } else if (region.getPos2() != null) { + point = region.getPos2(); + } else { + // No more selection + return null; + } + + // Just select the point. + posX = point.getBlockX(); + posY = point.getBlockY(); + posZ = point.getBlockZ(); + width = 1; + height = 1; + length = 1; + } + } else { + // We only support cuboid regions right now. + return null; + } + + int maxSize = getMaxServerCuiSize(); + + if (width > maxSize || length > maxSize || height > maxSize) { + // Structure blocks have a limit of maxSize^3 + return null; + } + + // Borrowed this math from FAWE + final Location location = player.getLocation(); + double rotX = location.getYaw(); + double rotY = location.getPitch(); + double xz = Math.cos(Math.toRadians(rotY)); + int x = (int) (location.getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12); + int z = (int) (location.getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12); + int y = Math.max( + player.getWorld().getMinY(), + Math.min(Math.min(player.getWorld().getMaxY(), posY + MAX_DISTANCE), posY + 3) + ); + + Map structureTag = new HashMap<>(); + + posX -= x; + posY -= y; + posZ -= z; + + if (Math.abs(posX) > MAX_DISTANCE || Math.abs(posY) > MAX_DISTANCE || Math.abs(posZ) > MAX_DISTANCE) { + // Structure blocks have a limit + return null; + } + + structureTag.put("name", new StringTag("worldedit:" + player.getName())); + structureTag.put("author", new StringTag(player.getName())); + structureTag.put("metadata", new StringTag("")); + structureTag.put("x", new IntTag(x)); + structureTag.put("y", new IntTag(y)); + structureTag.put("z", new IntTag(z)); + structureTag.put("posX", new IntTag(posX)); + structureTag.put("posY", new IntTag(posY)); + structureTag.put("posZ", new IntTag(posZ)); + structureTag.put("sizeX", new IntTag(width)); + structureTag.put("sizeY", new IntTag(height)); + structureTag.put("sizeZ", new IntTag(length)); + structureTag.put("rotation", new StringTag("NONE")); + structureTag.put("mirror", new StringTag("NONE")); + structureTag.put("mode", new StringTag("SAVE")); + structureTag.put("ignoreEntities", new ByteTag((byte) 1)); + structureTag.put("showboundingbox", new ByteTag((byte) 1)); + structureTag.put("id", new StringTag(BlockTypes.STRUCTURE_BLOCK.getId())); + + return BlockTypes.STRUCTURE_BLOCK.getDefaultState().toBaseBlock(new CompoundTag(structureTag)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java b/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java new file mode 100644 index 0000000..b33570c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.event; + +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.util.Identifiable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public class InteractionDebouncer { + private final Platform platform; + private final Map lastInteractions = new HashMap<>(); + + public InteractionDebouncer(Platform platform) { + this.platform = platform; + } + + public void clearInteraction(Identifiable player) { + lastInteractions.remove(player.getUniqueId()); + } + + public void setLastInteraction(Identifiable player, boolean result) { + lastInteractions.put(player.getUniqueId(), new Interaction(platform.getTickCount(), result)); + } + + public Optional getDuplicateInteractionResult(Identifiable player) { + Interaction last = lastInteractions.get(player.getUniqueId()); + if (last == null) { + return Optional.empty(); + } + + long now = platform.getTickCount(); + if (now - last.tick <= 1) { + return Optional.of(last.result); + } + + return Optional.empty(); + } + + private static class Interaction { + public final long tick; + public final boolean result; + + public Interaction(long tick, boolean result) { + this.tick = tick; + this.result = result; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/CompiledExpression.java b/src/main/java/com/sk89q/worldedit/internal/expression/CompiledExpression.java new file mode 100644 index 0000000..69b0335 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/CompiledExpression.java @@ -0,0 +1,29 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +/** + * Represents a "compiled" expression. + */ +public interface CompiledExpression { + + Double execute(ExecutionData executionData); + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/EvaluationException.java b/src/main/java/com/sk89q/worldedit/internal/expression/EvaluationException.java new file mode 100644 index 0000000..5552675 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/EvaluationException.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +/** + * Thrown when there's a problem during expression evaluation. + */ +public class EvaluationException extends ExpressionException { + + public EvaluationException(int position) { + super(position, getPrefix(position)); + } + + public EvaluationException(int position, String message, Throwable cause) { + super(position, getPrefix(position) + ": " + message, cause); + } + + public EvaluationException(int position, String message) { + super(position, getPrefix(position) + ": " + message); + } + + public EvaluationException(int position, Throwable cause) { + super(position, getPrefix(position), cause); + } + + private static String getPrefix(int position) { + return position < 0 ? "Evaluation error" : ("Evaluation error at " + (position + 1)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java b/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java new file mode 100644 index 0000000..d785929 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +import java.time.Instant; + +import static java.util.Objects.requireNonNull; + +public class ExecutionData { + + /** + * Special execution context for evaluating constant values. As long as no variables are used, + * it can be considered constant. + */ + public static final ExecutionData CONSTANT_EVALUATOR = new ExecutionData(null, null, Instant.MAX); + + private final SlotTable slots; + private final Functions functions; + private final Instant deadline; + + public ExecutionData(SlotTable slots, Functions functions, Instant deadline) { + this.slots = slots; + this.functions = functions; + this.deadline = deadline; + } + + public SlotTable getSlots() { + return requireNonNull(slots, "Cannot use variables in a constant"); + } + + public Functions getFunctions() { + return requireNonNull(functions, "Cannot use functions in a constant"); + } + + public Instant getDeadline() { + return deadline; + } + + public void checkDeadline() { + if (Instant.now().isAfter(deadline)) { + throw new ExpressionTimeoutException("Calculations exceeded time limit."); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java b/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java new file mode 100644 index 0000000..fb3e8f5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java @@ -0,0 +1,161 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.antlr.ExpressionLexer; +import com.sk89q.worldedit.antlr.ExpressionParser; +import com.sk89q.worldedit.internal.expression.invoke.ExpressionCompiler; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.misc.ParseCancellationException; +import org.antlr.v4.runtime.tree.ParseTreeWalker; + +import java.time.Instant; +import java.util.List; +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Compiles and evaluates expressions. + * + *

Supported operators:

+ * + *
    + *
  • Logical: &&, ||, ! (unary)
  • + *
  • Bitwise: ~ (unary), >>, <<
  • + *
  • Arithmetic: +, -, *, /, % (modulo), ^ (power), - (unary), --, ++ (prefix only)
  • + *
  • Comparison: <=, >=, >, <, ==, !=, ~= (near)
  • + *
+ * + *

Supported functions: abs, acos, asin, atan, atan2, cbrt, ceil, cos, cosh, + * exp, floor, ln, log, log10, max, max, min, min, rint, round, sin, sinh, + * sqrt, tan, tanh and more. (See the Functions class or the wiki)

+ * + *

Constants: e, pi

+ * + *

To compile an equation, run + * {@code Expression.compile("expression here", "var1", "var2"...)}. + * If you wish to run the equation multiple times, you can then optimize it, + * by calling {@link #optimize()}. You can then run the equation as many times + * as you want by calling {@link #evaluate(double...)}. You do not need to + * pass values for all slots specified while compiling. + * To query slots after evaluation, you can use the {@linkplain #getSlots() slot table}. + */ +public class Expression { + + private final String source; + private final SlotTable slots = new SlotTable(); + private final List providedSlots; + private final ExpressionParser.AllStatementsContext root; + private final Functions functions = Functions.create(); + private final CompiledExpression compiledExpression; + + public static Expression compile(String expression, String... variableNames) throws ExpressionException { + return new Expression(expression, variableNames); + } + + private Expression(String expression, String... variableNames) throws ExpressionException { + checkNotNull(expression, "Expression cannot be null."); + checkArgument(!expression.isEmpty(), "Expression cannot be empty string."); + this.source = expression; + slots.putSlot("e", new LocalSlot.Constant(Math.E)); + slots.putSlot("pi", new LocalSlot.Constant(Math.PI)); + slots.putSlot("true", new LocalSlot.Constant(1)); + slots.putSlot("false", new LocalSlot.Constant(0)); + + for (String variableName : variableNames) { + slots.initVariable(variableName) + .orElseThrow(() -> new ExpressionException(-1, + "Tried to overwrite identifier '" + variableName + "'")); + } + this.providedSlots = ImmutableList.copyOf(variableNames); + + CharStream cs = CharStreams.fromString(expression, ""); + ExpressionLexer lexer = new ExpressionLexer(cs); + lexer.removeErrorListeners(); + lexer.addErrorListener(new LexerErrorListener()); + CommonTokenStream tokens = new CommonTokenStream(lexer); + ExpressionParser parser = new ExpressionParser(tokens); + parser.removeErrorListeners(); + parser.addErrorListener(new ParserErrorListener()); + try { + root = parser.allStatements(); + Objects.requireNonNull(root, "Unable to parse root, but no exceptions?"); + } catch (ParseCancellationException e) { + throw new ParserException(parser.getState(), e); + } + ParseTreeWalker.DEFAULT.walk(new ExpressionValidator(slots.keySet(), functions), root); + this.compiledExpression = new ExpressionCompiler().compileExpression(root, functions); + } + + public double evaluate(double... values) throws EvaluationException { + return evaluate(values, WorldEdit.getInstance().getConfiguration().calculationTimeout); + } + + public double evaluate(double[] values, int timeout) throws EvaluationException { + for (int i = 0; i < values.length; ++i) { + String slotName = providedSlots.get(i); + LocalSlot.Variable slot = slots.getVariable(slotName) + .orElseThrow(() -> new EvaluationException(-1, + "Tried to assign to non-variable " + slotName + ".")); + + slot.setValue(values[i]); + } + + Instant deadline = Instant.now().plusMillis(timeout); + // evaluation exceptions are thrown out of this method + Double result = compiledExpression.execute(new ExecutionData(slots, functions, deadline)); + if (result == null) { + throw new EvaluationException(-1, "Expression must result in a value"); + } + return result; + } + + public void optimize() { + // TODO optimizing + } + + public String getSource() { + return source; + } + + @Override + public String toString() { + return root.toString(); + } + + public SlotTable getSlots() { + return slots; + } + + public ExpressionEnvironment getEnvironment() { + return functions.getEnvironment(); + } + + public void setEnvironment(ExpressionEnvironment environment) { + functions.setEnvironment(environment); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java new file mode 100644 index 0000000..061a520 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +/** + * Represents a way to access blocks in a world. Has to accept non-rounded coordinates. + */ +public interface ExpressionEnvironment { + + int getBlockType(double x, double y, double z); + + int getBlockData(double x, double y, double z); + + int getBlockTypeAbs(double x, double y, double z); + + int getBlockDataAbs(double x, double y, double z); + + int getBlockTypeRel(double x, double y, double z); + + int getBlockDataRel(double x, double y, double z); + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java new file mode 100644 index 0000000..deabf6b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +/** + * Thrown when there's a problem during any stage of the expression + * compilation or evaluation. + */ +public class ExpressionException extends RuntimeException { + + private final int position; + + public ExpressionException(int position) { + this.position = position; + } + + public ExpressionException(int position, String message, Throwable cause) { + super(message, cause); + this.position = position; + } + + public ExpressionException(int position, String message) { + super(message); + this.position = position; + } + + public ExpressionException(int position, Throwable cause) { + super(cause); + this.position = position; + } + + public int getPosition() { + return position; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java new file mode 100644 index 0000000..1fba749 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java @@ -0,0 +1,162 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +import com.sk89q.worldedit.antlr.ExpressionParser; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.sk89q.worldedit.antlr.ExpressionLexer.ID; + +public class ExpressionHelper { + + public static void check(boolean condition, ParserRuleContext ctx, String message) { + if (!condition) { + throw evalException(ctx, message); + } + } + + public static int getErrorPosition(Token token) { + return token.getCharPositionInLine(); + } + + public static EvaluationException evalException(ParserRuleContext ctx, String message) { + return evalException(ctx.start, message); + } + + public static EvaluationException evalException(Token token, String message) { + return new EvaluationException( + getErrorPosition(token), + message + ); + } + + public static void checkIterations(int iterations, ParserRuleContext ctx) { + check(iterations <= 256, ctx, "Loop exceeded 256 iterations"); + } + + public static MethodHandle resolveFunction(Functions functions, + ExpressionParser.FunctionCallContext ctx) { + String fnName = ctx.name.getText(); + Set matchingFns = functions.getMap().get(fnName); + check(!matchingFns.isEmpty(), ctx, "Unknown function '" + fnName + "'"); + for (MethodHandle function : matchingFns) { + if (function.isVarargsCollector()) { + int nParams = function.type().parameterCount(); + // last param is the array, turn that varargs + int keptParams = nParams - 1; + function = function.asCollector( + // collect into the last array + function.type().parameterType(nParams - 1), + // collect the variable args (args over kept) + ctx.args.size() - keptParams + ); + // re-wrap it for the inner arguments + function = function.asType(function.type().wrap()); + } + MethodType type = function.type(); + if (type.parameterCount() != ctx.args.size()) { + // skip non-matching function + continue; + } + for (int i = 0; i < ctx.args.size(); i++) { + ExpressionParser.ExpressionContext arg = ctx.args.get(i); + getArgumentHandleName(fnName, type, i, arg); + } + // good match! + return function; + } + // We matched no function, fail with appropriate message. + String possibleCounts = matchingFns.stream() + .map(mh -> mh.isVarargsCollector() + ? (mh.type().parameterCount() - 1) + "+" + : String.valueOf(mh.type().parameterCount())) + .collect(Collectors.joining("/")); + throw evalException(ctx, "Incorrect number of arguments for function '" + fnName + "', " + + "expected " + possibleCounts + ", " + + "got " + ctx.args.size()); + } + + // Special argument handle names + /** + * The argument should be wrapped in a {@link LocalSlot.Constant} before being passed. + */ + public static final String WRAPPED_CONSTANT = ""; + + /** + * If this argument needs a handle, returns the name of the handle needed. Otherwise, returns + * {@code null}. If {@code arg} isn't a valid handle reference, throws. + */ + public static String getArgumentHandleName(String fnName, MethodType type, int i, + ParserRuleContext arg) { + // Pass variable handle in for modification? + Class pType = type.parameterType(i); + Optional id = tryResolveId(arg); + if (pType == LocalSlot.Variable.class) { + // MUST be an id + check(id.isPresent(), arg, + "Function '" + fnName + "' requires a variable in parameter " + i); + return id.get(); + } else if (pType == LocalSlot.class) { + return id.orElse(WRAPPED_CONSTANT); + } + return null; + } + + private static Optional tryResolveId(ParserRuleContext arg) { + Optional wrappedExprContext = + tryAs(arg, ExpressionParser.WrappedExprContext.class); + if (wrappedExprContext.isPresent()) { + return tryResolveId(wrappedExprContext.get().expression()); + } + Token token = arg.start; + int tokenType = token.getType(); + boolean isId = arg.start == arg.stop && tokenType == ID; + return isId ? Optional.of(token.getText()) : Optional.empty(); + } + + private static Optional tryAs( + ParserRuleContext ctx, + Class rule + ) { + if (rule.isInstance(ctx)) { + return Optional.of(rule.cast(ctx)); + } + if (ctx.children.size() != 1) { + return Optional.empty(); + } + List ctxs = ctx.getRuleContexts(ParserRuleContext.class); + if (ctxs.size() != 1) { + return Optional.empty(); + } + return tryAs(ctxs.get(0), rule); + } + + private ExpressionHelper() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionTimeoutException.java b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionTimeoutException.java new file mode 100644 index 0000000..ff415eb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionTimeoutException.java @@ -0,0 +1,29 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +/** + * Thrown when an evaluation exceeds the timeout time. + */ +public class ExpressionTimeoutException extends EvaluationException { + public ExpressionTimeoutException(String message) { + super(-1, message); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionValidator.java b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionValidator.java new file mode 100644 index 0000000..b7c2edf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionValidator.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +import com.sk89q.worldedit.antlr.ExpressionBaseListener; +import com.sk89q.worldedit.antlr.ExpressionParser; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.check; +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.resolveFunction; + +class ExpressionValidator extends ExpressionBaseListener { + + private final Set variableNames = new HashSet<>(); + private final Functions functions; + + ExpressionValidator(Collection variableNames, + Functions functions) { + this.variableNames.addAll(variableNames); + this.functions = functions; + } + + private void bindVariable(String name) { + variableNames.add(name); + } + + @Override + public void enterAssignment(ExpressionParser.AssignmentContext ctx) { + bindVariable(ctx.target.getText()); + } + + @Override + public void enterSimpleForStatement(ExpressionParser.SimpleForStatementContext ctx) { + bindVariable(ctx.counter.getText()); + } + + @Override + public void enterIdExpr(ExpressionParser.IdExprContext ctx) { + String text = ctx.source.getText(); + check(variableNames.contains(text), ctx, + "Variable '" + text + "' is not bound"); + } + + @Override + public void enterFunctionCall(ExpressionParser.FunctionCallContext ctx) { + resolveFunction(functions, ctx); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java b/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java new file mode 100644 index 0000000..e18b093 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java @@ -0,0 +1,386 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.Multimaps; +import com.google.common.collect.SetMultimap; +import com.google.common.primitives.Doubles; +import com.sk89q.worldedit.internal.expression.LocalSlot.Variable; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.noise.PerlinNoise; +import com.sk89q.worldedit.math.noise.RidgedMultiFractalNoise; +import com.sk89q.worldedit.math.noise.VoronoiNoise; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.concurrent.ThreadLocalRandom; + +import static com.google.common.base.Preconditions.checkState; +import static java.lang.invoke.MethodHandles.filterReturnValue; +import static java.lang.invoke.MethodType.methodType; + +/** + * Contains all functions that can be used in expressions. + */ +public final class Functions { + + static Functions create() { + return new Functions(); + } + + private static final MethodHandle DOUBLE_VALUE; + + static { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + try { + DOUBLE_VALUE = lookup.findVirtual(Number.class, "doubleValue", + methodType(double.class)); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + + private static MethodHandle clean(MethodHandle handle) { + boolean wasVarargs = handle.isVarargsCollector(); + // box it all first + handle = handle.asType(handle.type().wrap()); + if (handle.type().returnType() != Double.class) { + // Ensure that the handle returns a Double, even if originally a Number + checkState(Number.class.isAssignableFrom(handle.type().returnType()), + "Function does not return a number"); + handle = handle.asType(handle.type().changeReturnType(Number.class)); + handle = filterReturnValue(handle, DOUBLE_VALUE); + handle = handle.asType(handle.type().wrap()); + } + // return vararg-ity + if (wasVarargs) { + handle = handle.asVarargsCollector( + handle.type().parameterType(handle.type().parameterCount() - 1) + ); + } + return handle; + } + + private static void addMathHandles( + SetMultimap map, + MethodHandles.Lookup lookup + ) throws NoSuchMethodException, IllegalAccessException { + // double (double) functions + for (String name : ImmutableList.of( + "sin", "cos", "tan", "asin", "acos", "atan", + "sinh", "cosh", "tanh", "sqrt", "cbrt", "abs", + "ceil", "floor", "rint", "exp", "log", "log10" + )) { + map.put(name, lookup.findStatic(Math.class, name, + methodType(double.class, double.class))); + } + // Alias ln -> log + map.put("ln", lookup.findStatic(Math.class, "log", + methodType(double.class, double.class))); + map.put("round", lookup.findStatic(Math.class, "round", + methodType(long.class, double.class))); + + map.put("atan2", lookup.findStatic(Math.class, "atan2", + methodType(double.class, double.class, double.class))); + + // Special cases: we accept varargs for these + map.put("min", lookup.findStatic(Doubles.class, "min", + methodType(double.class, double[].class)) + .asVarargsCollector(double[].class)); + map.put("max", lookup.findStatic(Doubles.class, "max", + methodType(double.class, double[].class)) + .asVarargsCollector(double[].class)); + } + + private static void addStaticFunctionHandles( + SetMultimap map, + MethodHandles.Lookup lookup + ) throws NoSuchMethodException, IllegalAccessException { + map.put("rotate", lookup.findStatic(Functions.class, "rotate", + methodType(double.class, Variable.class, Variable.class, double.class))); + map.put("swap", lookup.findStatic(Functions.class, "swap", + methodType(double.class, Variable.class, Variable.class))); + map.put("gmegabuf", lookup.findStatic(Functions.class, "gmegabuf", + methodType(double.class, double.class))); + map.put("gmegabuf", lookup.findStatic(Functions.class, "gmegabuf", + methodType(double.class, double.class, double.class))); + map.put("gclosest", lookup.findStatic(Functions.class, "gclosest", + methodType(double.class, double.class, double.class, double.class, double.class, + double.class, double.class))); + map.put("random", lookup.findStatic(Functions.class, "random", + methodType(double.class))); + map.put("randint", lookup.findStatic(Functions.class, "randint", + methodType(double.class, double.class))); + map.put("perlin", lookup.findStatic(Functions.class, "perlin", + methodType(double.class, double.class, double.class, double.class, double.class, + double.class, double.class, double.class))); + map.put("voronoi", lookup.findStatic(Functions.class, "voronoi", + methodType(double.class, double.class, double.class, double.class, double.class, + double.class))); + map.put("ridgedmulti", lookup.findStatic(Functions.class, "ridgedmulti", + methodType(double.class, double.class, double.class, double.class, double.class, + double.class, double.class))); + } + + private void addInstanceFunctionHandles( + SetMultimap map, + MethodHandles.Lookup lookup + ) throws NoSuchMethodException, IllegalAccessException { + map.put("megabuf", lookup.findSpecial(Functions.class, "megabuf", + methodType(double.class, double.class), Functions.class) + .bindTo(this)); + map.put("megabuf", lookup.findSpecial(Functions.class, "megabuf", + methodType(double.class, double.class, double.class), Functions.class) + .bindTo(this)); + map.put("closest", lookup.findSpecial(Functions.class, "closest", + methodType(double.class, double.class, double.class, double.class, double.class, + double.class, double.class), Functions.class) + .bindTo(this)); + + // rely on expression field + map.put("query", lookup.findSpecial(Functions.class, "query", + methodType(double.class, double.class, double.class, double.class, LocalSlot.class, + LocalSlot.class), Functions.class) + .bindTo(this)); + map.put("queryAbs", lookup.findSpecial(Functions.class, "queryAbs", + methodType(double.class, double.class, double.class, double.class, LocalSlot.class, + LocalSlot.class), Functions.class) + .bindTo(this)); + map.put("queryRel", lookup.findSpecial(Functions.class, "queryRel", + methodType(double.class, double.class, double.class, double.class, LocalSlot.class, + LocalSlot.class), Functions.class) + .bindTo(this)); + } + + private static double rotate(Variable x, Variable y, double angle) { + final double cosF = Math.cos(angle); + final double sinF = Math.sin(angle); + + final double xOld = x.getValue(); + final double yOld = y.getValue(); + + x.setValue(xOld * cosF - yOld * sinF); + y.setValue(xOld * sinF + yOld * cosF); + + return 0.0; + } + + private static double swap(Variable x, Variable y) { + final double tmp = x.getValue(); + + x.setValue(y.getValue()); + y.setValue(tmp); + + return 0.0; + } + + + private static final Int2ObjectMap globalMegaBuffer = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap megaBuffer = new Int2ObjectOpenHashMap<>(); + private final SetMultimap map; + private ExpressionEnvironment environment; + + private Functions() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + SetMultimap map = HashMultimap.create(); + try { + addMathHandles(map, lookup); + addStaticFunctionHandles(map, lookup); + addInstanceFunctionHandles(map, lookup); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + this.map = ImmutableSetMultimap.copyOf( + Multimaps.transformValues(map, Functions::clean) + ); + } + + public SetMultimap getMap() { + return map; + } + + public ExpressionEnvironment getEnvironment() { + return environment; + } + + public void setEnvironment(ExpressionEnvironment environment) { + this.environment = environment; + } + + private static double[] getSubBuffer(Int2ObjectMap megabuf, int key) { + return megabuf.computeIfAbsent(key, k -> new double[1024]); + } + + private static double getBufferItem(final Int2ObjectMap megabuf, final int index) { + return getSubBuffer(megabuf, index & ~1023)[index & 1023]; + } + + private static double setBufferItem(final Int2ObjectMap megabuf, final int index, double value) { + return getSubBuffer(megabuf, index & ~1023)[index & 1023] = value; + } + + private static double gmegabuf(double index) { + return getBufferItem(globalMegaBuffer, (int) index); + } + + private static double gmegabuf(double index, double value) { + return setBufferItem(globalMegaBuffer, (int) index, value); + } + + private double megabuf(double index) { + return getBufferItem(megaBuffer, (int) index); + } + + private double megabuf(double index, double value) { + return setBufferItem(megaBuffer, (int) index, value); + } + + private double closest(double x, double y, double z, double index, double count, double stride) { + return findClosest( + megaBuffer, x, y, z, (int) index, (int) count, (int) stride + ); + } + + private static double gclosest(double x, double y, double z, double index, double count, double stride) { + return findClosest( + globalMegaBuffer, x, y, z, (int) index, (int) count, (int) stride + ); + } + + private static double findClosest(Int2ObjectMap megabuf, double x, double y, double z, int index, int count, int stride) { + int closestIndex = -1; + double minDistanceSquared = Double.MAX_VALUE; + + for (int i = 0; i < count; ++i) { + double currentX = getBufferItem(megabuf, index) - x; + double currentY = getBufferItem(megabuf, index + 1) - y; + double currentZ = getBufferItem(megabuf, index + 2) - z; + + double currentDistanceSquared = currentX * currentX + currentY * currentY + currentZ * currentZ; + + if (currentDistanceSquared < minDistanceSquared) { + minDistanceSquared = currentDistanceSquared; + closestIndex = index; + } + + index += stride; + } + + return closestIndex; + } + + private static double random() { + return ThreadLocalRandom.current().nextDouble(); + } + + private static double randint(double max) { + return ThreadLocalRandom.current().nextInt((int) Math.floor(max)); + } + + private static final ThreadLocal localPerlin = ThreadLocal.withInitial(PerlinNoise::new); + + private static double perlin(double seed, double x, double y, double z, + double frequency, double octaves, double persistence) { + PerlinNoise perlin = localPerlin.get(); + try { + perlin.setSeed((int) seed); + perlin.setFrequency(frequency); + perlin.setOctaveCount((int) octaves); + perlin.setPersistence(persistence); + } catch (IllegalArgumentException e) { + throw new EvaluationException(0, "Perlin noise error: " + e.getMessage()); + } + return perlin.noise(Vector3.at(x, y, z)); + } + + private static final ThreadLocal localVoronoi = ThreadLocal.withInitial(VoronoiNoise::new); + + private static double voronoi(double seed, double x, double y, double z, double frequency) { + VoronoiNoise voronoi = localVoronoi.get(); + try { + voronoi.setSeed((int) seed); + voronoi.setFrequency(frequency); + } catch (IllegalArgumentException e) { + throw new EvaluationException(0, "Voronoi error: " + e.getMessage()); + } + return voronoi.noise(Vector3.at(x, y, z)); + } + + private static final ThreadLocal localRidgedMulti = ThreadLocal.withInitial(RidgedMultiFractalNoise::new); + + private static double ridgedmulti(double seed, double x, double y, double z, + double frequency, double octaves) { + RidgedMultiFractalNoise ridgedMulti = localRidgedMulti.get(); + try { + ridgedMulti.setSeed((int) seed); + ridgedMulti.setFrequency(frequency); + ridgedMulti.setOctaveCount((int) octaves); + } catch (IllegalArgumentException e) { + throw new EvaluationException(0, "Ridged multi error: " + e.getMessage()); + } + return ridgedMulti.noise(Vector3.at(x, y, z)); + } + + private static double queryInternal(LocalSlot type, LocalSlot data, double typeId, double dataValue) { + // Compare to input values and determine return value + // -1 is a wildcard, always true + double ret = ((type.getValue() == -1 || typeId == type.getValue()) + && (data.getValue() == -1 || dataValue == data.getValue())) ? 1.0 : 0.0; + + if (type instanceof Variable) { + ((Variable) type).setValue(typeId); + } + if (data instanceof Variable) { + ((Variable) data).setValue(dataValue); + } + + return ret; + } + + private double query(double x, double y, double z, LocalSlot type, LocalSlot data) { + // Read values from world + final double typeId = environment.getBlockType(x, y, z); + final double dataValue = environment.getBlockData(x, y, z); + + return queryInternal(type, data, typeId, dataValue); + } + + private double queryAbs(double x, double y, double z, LocalSlot type, LocalSlot data) { + // Read values from world + final double typeId = environment.getBlockTypeAbs(x, y, z); + final double dataValue = environment.getBlockDataAbs(x, y, z); + + return queryInternal(type, data, typeId, dataValue); + } + + private double queryRel(double x, double y, double z, LocalSlot type, LocalSlot data) { + // Read values from world + final double typeId = environment.getBlockTypeRel(x, y, z); + final double dataValue = environment.getBlockDataRel(x, y, z); + + return queryInternal(type, data, typeId, dataValue); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/Identifiable.java b/src/main/java/com/sk89q/worldedit/internal/expression/Identifiable.java new file mode 100644 index 0000000..c587894 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/Identifiable.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +/** + * A common superinterface for everything passed to parser processors. + */ +public interface Identifiable { + + /** + * Returns a character that helps identify the token, pseudo-token or invokable in question. + * + *

+     * Tokens:
+     * i - IdentifierToken
+     * 0 - NumberToken
+     * o - OperatorToken
+     * \0 - NullToken
+     * CharacterTokens are returned literally
+     *
+     * PseudoTokens:
+     * p - UnaryOperator
+     * V - UnboundVariable
+     *
+     * Nodes:
+     * c - Constant
+     * v - Variable
+     * f - Function
+     * l - LValueFunction
+     * s - Sequence
+     * I - Conditional
+     * w - While
+     * F - For
+     * r - Return
+     * b - Break (includes continue)
+     * S - SimpleFor
+     * C - Switch
+     * 
+ */ + char id(); + + int getPosition(); + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/LexerErrorListener.java b/src/main/java/com/sk89q/worldedit/internal/expression/LexerErrorListener.java new file mode 100644 index 0000000..0fd0101 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/LexerErrorListener.java @@ -0,0 +1,31 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; + +class LexerErrorListener extends BaseErrorListener { + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + throw new LexerException(charPositionInLine, msg); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/LexerException.java b/src/main/java/com/sk89q/worldedit/internal/expression/LexerException.java new file mode 100644 index 0000000..01e51e5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/LexerException.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +/** + * Thrown when the lexer encounters a problem. + */ +public class LexerException extends ExpressionException { + + public LexerException(int position) { + super(position, getPrefix(position)); + } + + public LexerException(int position, String message, Throwable cause) { + super(position, getPrefix(position) + ": " + message, cause); + } + + public LexerException(int position, String message) { + super(position, getPrefix(position) + ": " + message); + } + + public LexerException(int position, Throwable cause) { + super(position, getPrefix(position), cause); + } + + private static String getPrefix(int position) { + return position < 0 ? "Lexer error" : ("Lexer error at " + (position + 1)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java b/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java new file mode 100644 index 0000000..8e81a55 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +/** + * Represents the metadata for a named local slot. + */ +public interface LocalSlot { + + final class Constant implements LocalSlot { + private final double value; + + public Constant(double value) { + this.value = value; + } + + @Override + public double getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + } + + final class Variable implements LocalSlot { + private double value; + + public Variable(double value) { + this.value = value; + } + + public void setValue(double value) { + this.value = value; + } + + @Override + public double getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + } + + double getValue(); + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/ParserErrorListener.java b/src/main/java/com/sk89q/worldedit/internal/expression/ParserErrorListener.java new file mode 100644 index 0000000..e69635d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/ParserErrorListener.java @@ -0,0 +1,31 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; + +class ParserErrorListener extends BaseErrorListener { + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + throw new ParserException(charPositionInLine, msg); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/ParserException.java b/src/main/java/com/sk89q/worldedit/internal/expression/ParserException.java new file mode 100644 index 0000000..c8ea871 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/ParserException.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +/** + * Thrown when the parser encounters a problem. + */ +public class ParserException extends ExpressionException { + + public ParserException(int position) { + super(position, getPrefix(position)); + } + + public ParserException(int position, String message, Throwable cause) { + super(position, getPrefix(position) + ": " + message, cause); + } + + public ParserException(int position, String message) { + super(position, getPrefix(position) + ": " + message); + } + + public ParserException(int position, Throwable cause) { + super(position, getPrefix(position), cause); + } + + private static String getPrefix(int position) { + return position < 0 ? "Parser error" : ("Parser error at " + (position + 1)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java b/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java new file mode 100644 index 0000000..c69de48 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java @@ -0,0 +1,60 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression; + +import java.util.*; + +public class SlotTable { + + private final Map slots = new HashMap<>(); + + public Set keySet() { + return slots.keySet(); + } + + public void putSlot(String name, LocalSlot slot) { + slots.put(name, slot); + } + + public boolean containsSlot(String name) { + return slots.containsKey(name); + } + + public Optional initVariable(String name) { + slots.computeIfAbsent(name, n -> new LocalSlot.Variable(0)); + return getVariable(name); + } + + public Optional getSlot(String name) { + return Optional.ofNullable(slots.get(name)); + } + + public Optional getVariable(String name) { + return getSlot(name) + .filter(LocalSlot.Variable.class::isInstance) + .map(LocalSlot.Variable.class::cast); + } + + public OptionalDouble getSlotValue(String name) { + LocalSlot slot = slots.get(name); + return slot == null ? OptionalDouble.empty() : OptionalDouble.of(slot.getValue()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/invoke/BreakException.java b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/BreakException.java new file mode 100644 index 0000000..519c06c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/BreakException.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression.invoke; + +/** + * Thrown when a break or continue is encountered. + * Loop constructs catch this exception. + */ +class BreakException extends RuntimeException { + + public static final BreakException BREAK = new BreakException(false); + public static final BreakException CONTINUE = new BreakException(true); + + public final boolean doContinue; + + private BreakException(boolean doContinue) { + super(doContinue ? "'continue' encountered outside a loop" : "'break' encountered outside a loop", + null, true, false); + + this.doContinue = doContinue; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java new file mode 100644 index 0000000..cba1d9e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java @@ -0,0 +1,667 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression.invoke; + +import com.sk89q.worldedit.antlr.ExpressionBaseVisitor; +import com.sk89q.worldedit.antlr.ExpressionParser; +import com.sk89q.worldedit.internal.expression.*; +import it.unimi.dsi.fastutil.doubles.Double2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.doubles.Double2ObjectMap; +import org.antlr.v4.runtime.CommonToken; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.RuleNode; +import org.antlr.v4.runtime.tree.TerminalNode; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.function.DoubleBinaryOperator; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static com.sk89q.worldedit.antlr.ExpressionLexer.*; +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.WRAPPED_CONSTANT; +import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.*; +import static java.lang.invoke.MethodType.methodType; + +/** + * The brains of {@link ExpressionCompiler}. + */ +class CompilingVisitor extends ExpressionBaseVisitor { + + /* + * General idea is that we don't need to pass around variables, they're all in ExecutionData. + * We do need to pass that around, so most MethodHandles will be of the type + * (ExecutionData)Double, with a few as (ExecutionData,Double)Double where it needs an existing + * value passed in. EVERY handle returned from an overridden method must be of the first type. + */ + private final Functions functions; + + CompilingVisitor(Functions functions) { + this.functions = functions; + } + + private Token extractToken(ParserRuleContext ctx) { + List children = ctx.children.stream() + .filter(TerminalNode.class::isInstance) + .map(TerminalNode.class::cast) + .collect(Collectors.toList()); + ExpressionHelper.check(children.size() == 1, ctx, "Expected exactly one token, got " + children.size()); + return children.get(0).getSymbol(); + } + + private ExecNode evaluate(ParserRuleContext ctx) { + MethodHandle mh = ctx.accept(this); + if (ctx.parent instanceof ParserRuleContext) { + checkHandle(mh, (ParserRuleContext) ctx.parent); + } + return new ExecNode(ctx, mh); + } + + private void checkHandle(MethodHandle mh, ParserRuleContext ctx) { + ExpressionHelper.check(mh.type().equals(ExpressionHandles.COMPILED_EXPRESSION_SIG), ctx, + "Incorrect type returned from handler for " + ctx.getClass()); + } + + private MethodHandle evaluateForNamedValue(ParserRuleContext ctx, String name) { + MethodHandle guard = MethodHandles.guardWithTest( + // if result is null + IS_NULL.asType(methodType(boolean.class, Double.class)), + // throw appropriate exception, dropping `result` argument + MethodHandles.dropArguments( + ExpressionHandles.throwEvalException(ctx, "Invalid expression for " + name), 0, Double.class + ), + // else return the argument we were passed + MethodHandles.identity(Double.class) + ); + // now pass `result` into `guard` + MethodHandle result = evaluate(ctx).handle; + return MethodHandles.collectArguments(guard, 0, result); + } + + private MethodHandle evaluateForValue(ParserRuleContext ctx) { + return evaluateForNamedValue(ctx, "a value"); + } + + private MethodHandle evaluateBoolean(ParserRuleContext boolExpression) { + MethodHandle value = evaluateForNamedValue(boolExpression, "a boolean"); + // Pass `value` into converter, returns (ExecutionData)boolean; + return MethodHandles.collectArguments( + DOUBLE_TO_BOOL, 0, value + ); + } + + private MethodHandle evaluateConditional(ParserRuleContext condition, + ParserRuleContext trueBranch, + ParserRuleContext falseBranch) { + // easiest one of the bunch + return MethodHandles.guardWithTest( + evaluateBoolean(condition), + trueBranch == null ? NULL_DOUBLE : evaluate(trueBranch).handle, + falseBranch == null ? NULL_DOUBLE : evaluate(falseBranch).handle + ); + } + + @Override + public MethodHandle visitIfStatement(ExpressionParser.IfStatementContext ctx) { + return evaluateConditional(ctx.condition, ctx.trueBranch, ctx.falseBranch); + } + + @Override + public MethodHandle visitTernaryExpr(ExpressionParser.TernaryExprContext ctx) { + return evaluateConditional(ctx.condition, ctx.trueBranch, ctx.falseBranch); + } + + @Override + public MethodHandle visitWhileStatement(ExpressionParser.WhileStatementContext ctx) { + return ExpressionHandles.whileLoop( + evaluateBoolean(ctx.condition), + evaluate(ctx.body) + ); + } + + @Override + public MethodHandle visitDoStatement(ExpressionParser.DoStatementContext ctx) { + return ExpressionHandles.doWhileLoop( + evaluateBoolean(ctx.condition), + evaluate(ctx.body) + ); + } + + @Override + public MethodHandle visitForStatement(ExpressionParser.ForStatementContext ctx) { + return ExpressionHandles.forLoop( + evaluate(ctx.init).handle, + evaluateBoolean(ctx.condition), + evaluate(ctx.body), + evaluate(ctx.update).handle + ); + } + + @Override + public MethodHandle visitSimpleForStatement(ExpressionParser.SimpleForStatementContext ctx) { + return ExpressionHandles.simpleForLoop( + evaluateForValue(ctx.first), + evaluateForValue(ctx.last), + ctx.counter, + evaluate(ctx.body) + ); + } + + private static final MethodHandle BREAK_STATEMENT = + ExpressionHandles.dropData(MethodHandles.throwException(Double.class, BreakException.class) + .bindTo(BreakException.BREAK)); + private static final MethodHandle CONTINUE_STATEMENT = + ExpressionHandles.dropData(MethodHandles.throwException(Double.class, BreakException.class) + .bindTo(BreakException.CONTINUE)); + + @Override + public MethodHandle visitBreakStatement(ExpressionParser.BreakStatementContext ctx) { + return BREAK_STATEMENT; + } + + @Override + public MethodHandle visitContinueStatement(ExpressionParser.ContinueStatementContext ctx) { + return CONTINUE_STATEMENT; + } + + // MH = (Double)Double + // takes the double to return, conveniently has Double return type + private static final MethodHandle RETURN_STATEMENT_BASE = MethodHandles.filterReturnValue( + // take the (Double)ReturnException constructor + ExpressionHandles.NEW_RETURN_EXCEPTION, + // and map the return type to Double by throwing it + MethodHandles.throwException(Double.class, ReturnException.class) + ); + + @Override + public MethodHandle visitReturnStatement(ExpressionParser.ReturnStatementContext ctx) { + return MethodHandles.filterArguments( + // take the (Double)Double return statement + RETURN_STATEMENT_BASE, + 0, + // map the Double back to ExecutionData via the returnValue + evaluate(ctx.value).handle + ); + } + + @Override + public MethodHandle visitSwitchStatement(ExpressionParser.SwitchStatementContext ctx) { + Double2ObjectMap cases = new Double2ObjectLinkedOpenHashMap<>(ctx.labels.size()); + ExecNode defaultCase = null; + for (int i = 0; i < ctx.labels.size(); i++) { + ExpressionParser.SwitchLabelContext label = ctx.labels.get(i); + ExpressionParser.StatementsContext body = ctx.bodies.get(i); + ExecNode node = evaluate(body); + if (label instanceof ExpressionParser.CaseContext) { + ExpressionParser.CaseContext caseContext = (ExpressionParser.CaseContext) label; + double key = (double) ExpressionHandles.constantInvoke(evaluateForValue(caseContext.constant)); + ExpressionHelper.check(!cases.containsKey(key), body, "Duplicate cases detected."); + cases.put(key, node); + } else { + ExpressionHelper.check(defaultCase == null, body, "Duplicate default cases detected."); + defaultCase = node; + } + } + return ExpressionHandles.switchStatement(cases, evaluateForValue(ctx.target), defaultCase); + } + + @Override + public MethodHandle visitExpressionStatement(ExpressionParser.ExpressionStatementContext ctx) { + return evaluate(ctx.expression()).handle; + } + + @Override + public MethodHandle visitPostCrementExpr(ExpressionParser.PostCrementExprContext ctx) { + Token target = ctx.target; + int opType = ctx.op.getType(); + return ExpressionHandles.call(data -> { + LocalSlot.Variable variable = ExpressionHandles.getVariable(data, target); + double value = variable.getValue(); + double result = value; + if (opType == INCREMENT) { + value++; + } else { + value--; + } + variable.setValue(value); + return result; + }); + } + + @Override + public MethodHandle visitPreCrementExpr(ExpressionParser.PreCrementExprContext ctx) { + Token target = ctx.target; + int opType = ctx.op.getType(); + return ExpressionHandles.call(data -> { + LocalSlot.Variable variable = ExpressionHandles.getVariable(data, target); + double value = variable.getValue(); + if (opType == INCREMENT) { + value++; + } else { + value--; + } + variable.setValue(value); + return value; + }); + } + + @Override + public MethodHandle visitPlusMinusExpr(ExpressionParser.PlusMinusExprContext ctx) { + MethodHandle value = evaluateForValue(ctx.expr); + switch (ctx.op.getType()) { + case PLUS: + return value; + case MINUS: + return ExpressionHandles.call(data -> + -(double) ExpressionHandles.standardInvoke(value, data) + ); + default: + throw ExpressionHelper.evalException(ctx, "Invalid text for plus/minus expr: " + ctx.op.getText()); + } + } + + @Override + public MethodHandle visitNotExpr(ExpressionParser.NotExprContext ctx) { + MethodHandle expr = evaluateBoolean(ctx.expr); + return ExpressionHandles.call(data -> + ExpressionHandles.boolToDouble(!(boolean) ExpressionHandles.standardInvoke(expr, data)) + ); + } + + @Override + public MethodHandle visitComplementExpr(ExpressionParser.ComplementExprContext ctx) { + MethodHandle expr = evaluateForValue(ctx.expr); + // Looks weird. In order: + // - Convert back to double from following long + // - Convert to long from double value + // - Convert from Object to Double to double. + return ExpressionHandles.call(data -> + (double) ~(long) (double) ExpressionHandles.standardInvoke(expr, data) + ); + } + + @Override + public MethodHandle visitConditionalAndExpr(ExpressionParser.ConditionalAndExprContext ctx) { + MethodHandle left = evaluateBoolean(ctx.left); + MethodHandle right = evaluateForValue(ctx.right); + return MethodHandles.guardWithTest( + left, + right, + ExpressionHandles.dropData( + MethodHandles.constant(Double.class, ExpressionHandles.boolToDouble(false)) + ) + ); + } + + @Override + public MethodHandle visitConditionalOrExpr(ExpressionParser.ConditionalOrExprContext ctx) { + MethodHandle left = evaluateForValue(ctx.left); + MethodHandle right = evaluateForValue(ctx.right); + // Inject left as primary condition, on failure take right with data parameter + // logic = (Double,ExecutionData)Double + MethodHandle logic = MethodHandles.guardWithTest( + // data arg dropped implicitly -- (Double)boolean; + DOUBLE_TO_BOOL, + // drop data arg -- (Double,ExecutionData)Double; + MethodHandles.dropArguments( + MethodHandles.identity(Double.class), 1, ExecutionData.class + ), + // drop left arg, call right -- (Double,ExecutionData)Double; + MethodHandles.dropArguments( + right, 0, Double.class + ) + ); + // mixed = (ExecutionData,ExecutionData)Double + MethodHandle mixed = MethodHandles.collectArguments( + logic, 0, left + ); + // Deduplicate ExecutionData + return ExpressionHandles.dedupData(mixed); + } + + private MethodHandle evaluateBinary(ParserRuleContext left, + ParserRuleContext right, + DoubleBinaryOperator op) { + MethodHandle mhLeft = evaluateForValue(left); + MethodHandle mhRight = evaluateForValue(right); + // Map two data args to two double args, then evaluate op + MethodHandle doubleData = MethodHandles.filterArguments( + CALL_BINARY_OP.bindTo(op), 0, + unboxDoubles(mhLeft), unboxDoubles(mhRight) + ); + return ExpressionHandles.dedupData(doubleData); + } + + private MethodHandle evaluateBinary(ParserRuleContext left, + ParserRuleContext right, + Supplier op) { + return evaluateBinary(left, right, op.get()); + } + + @Override + public MethodHandle visitPowerExpr(ExpressionParser.PowerExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, Math::pow); + } + + @Override + public MethodHandle visitMultiplicativeExpr(ExpressionParser.MultiplicativeExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, () -> { + switch (ctx.op.getType()) { + case TIMES: + return (l, r) -> l * r; + case DIVIDE: + return (l, r) -> l / r; + case MODULO: + return (l, r) -> l % r; + default: + throw ExpressionHelper.evalException(ctx, "Invalid text for multiplicative expr: " + ctx.op.getText()); + } + }); + } + + @Override + public MethodHandle visitAddExpr(ExpressionParser.AddExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, () -> { + switch (ctx.op.getType()) { + case PLUS: + return Double::sum; + case MINUS: + return (l, r) -> l - r; + default: + throw ExpressionHelper.evalException(ctx, "Invalid text for additive expr: " + ctx.op.getText()); + } + }); + } + + @Override + public MethodHandle visitShiftExpr(ExpressionParser.ShiftExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, () -> { + switch (ctx.op.getType()) { + case LEFT_SHIFT: + return (l, r) -> (double) ((long) l << (long) r); + case RIGHT_SHIFT: + return (l, r) -> (double) ((long) l >> (long) r); + default: + throw ExpressionHelper.evalException(ctx, "Invalid text for shift expr: " + ctx.op.getText()); + } + }); + } + + @Override + public MethodHandle visitRelationalExpr(ExpressionParser.RelationalExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, () -> { + switch (ctx.op.getType()) { + case LESS_THAN: + return (l, r) -> ExpressionHandles.boolToDouble(l < r); + case LESS_THAN_OR_EQUAL: + return (l, r) -> ExpressionHandles.boolToDouble(l <= r); + case GREATER_THAN: + return (l, r) -> ExpressionHandles.boolToDouble(l > r); + case GREATER_THAN_OR_EQUAL: + return (l, r) -> ExpressionHandles.boolToDouble(l >= r); + default: + throw ExpressionHelper.evalException(ctx, "Invalid text for relational expr: " + ctx.op.getText()); + } + }); + } + + @Override + public MethodHandle visitEqualityExpr(ExpressionParser.EqualityExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, () -> { + switch (ctx.op.getType()) { + case EQUAL: + return (l, r) -> ExpressionHandles.boolToDouble(l == r); + case NOT_EQUAL: + return (l, r) -> ExpressionHandles.boolToDouble(l != r); + case NEAR: + return (l, r) -> ExpressionHandles.boolToDouble(almostEqual2sComplement(l, r)); + default: + throw ExpressionHelper.evalException(ctx, "Invalid text for equality expr: " + ctx.op.getText()); + } + }); + } + + // Usable AlmostEqual function, based on http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm + private static boolean almostEqual2sComplement(double a, double b) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + //assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); // this is for floats, not doubles + + long aLong = Double.doubleToRawLongBits(a); + // Make aLong lexicographically ordered as a twos-complement long + if (aLong < 0) { + aLong = 0x8000000000000000L - aLong; + } + + long bLong = Double.doubleToRawLongBits(b); + // Make bLong lexicographically ordered as a twos-complement long + if (bLong < 0) { + bLong = 0x8000000000000000L - bLong; + } + + final long longDiff = Math.abs(aLong - bLong); + return longDiff <= 450359963L; + } + + @Override + public MethodHandle visitPostfixExpr(ExpressionParser.PostfixExprContext ctx) { + MethodHandle value = evaluateForValue(ctx.expr); + if (ctx.op.getType() == EXCLAMATION_MARK) { + return ExpressionHandles.call(data -> + factorial((double) ExpressionHandles.standardInvoke(value, data)) + ); + } + throw ExpressionHelper.evalException(ctx, + "Invalid text for post-unary expr: " + ctx.op.getText()); + } + + private static final double[] factorials = new double[171]; + + static { + factorials[0] = 1; + for (int i = 1; i < factorials.length; ++i) { + factorials[i] = factorials[i - 1] * i; + } + } + + private static double factorial(double x) throws EvaluationException { + final int n = (int) x; + + if (n < 0) { + return 0; + } + + if (n >= factorials.length) { + return Double.POSITIVE_INFINITY; + } + + return factorials[n]; + } + + @Override + public MethodHandle visitAssignment(ExpressionParser.AssignmentContext ctx) { + int type = extractToken(ctx.assignmentOperator()).getType(); + Token target = ctx.target; + MethodHandle getArg = evaluateForValue(ctx.expression()); + return ExpressionHandles.call(data -> { + double value; + double arg = (double) ExpressionHandles.standardInvoke(getArg, data); + LocalSlot.Variable variable; + if (type == ASSIGN) { + variable = ExpressionHandles.initVariable(data, target); + value = arg; + } else { + variable = ExpressionHandles.getVariable(data, target); + value = variable.getValue(); + switch (type) { + case POWER_ASSIGN: + value = Math.pow(value, arg); + break; + case TIMES_ASSIGN: + value *= arg; + break; + case DIVIDE_ASSIGN: + value /= arg; + break; + case MODULO_ASSIGN: + value %= arg; + break; + case PLUS_ASSIGN: + value += arg; + break; + case MINUS_ASSIGN: + value -= arg; + break; + default: + throw ExpressionHelper.evalException(ctx, "Invalid text for assign expr: " + + ctx.assignmentOperator().getText()); + } + } + variable.setValue(value); + return value; + }); + } + + @Override + public MethodHandle visitFunctionCall(ExpressionParser.FunctionCallContext ctx) { + MethodHandle handle = ExpressionHelper.resolveFunction(functions, ctx); + String fnName = ctx.name.getText(); + MethodHandle[] arguments = new MethodHandle[ctx.args.size()]; + for (int i = 0; i < arguments.length; i++) { + ExpressionParser.ExpressionContext arg = ctx.args.get(i); + MethodHandle transformed = getArgument(fnName, handle.type(), i, arg); + Class ptype = handle.type().parameterType(i); + Class rtype = transformed.type().returnType(); + if (ptype != rtype && ptype.isAssignableFrom(rtype)) { + // need to upcast + transformed = transformed.asType(transformed.type().changeReturnType(ptype)); + } + arguments[i] = transformed; + } + // Take each of our data accepting arguments, apply them over the source method + MethodHandle manyData = MethodHandles.filterArguments(handle, 0, arguments); + // Collapse every data into one argument + int[] permutation = new int[arguments.length]; + return MethodHandles.permuteArguments( + manyData, ExpressionHandles.COMPILED_EXPRESSION_SIG, permutation + ); + } + + // MH: (ExecutionData)T; (depends on target) + private MethodHandle getArgument(String fnName, MethodType type, int i, ParserRuleContext arg) { + // Pass variable handle in for modification? + String handleName = ExpressionHelper.getArgumentHandleName(fnName, type, i, arg); + if (handleName == null) { + return evaluateForValue(arg); + } + if (handleName.equals(WRAPPED_CONSTANT)) { + // pass arg into new LocalSlot.Constant + MethodHandle filter = evaluateForValue(arg); + filter = filter.asType(filter.type().unwrap()); + return MethodHandles.collectArguments( + NEW_LS_CONSTANT, 0, filter + ); + } + // small hack + CommonToken fake = new CommonToken(arg.start); + fake.setText(handleName); + return ExpressionHandles.mhGetVariable(fake); + } + + @Override + public MethodHandle visitConstantExpression(ExpressionParser.ConstantExpressionContext ctx) { + return ExpressionHandles.dropData( + MethodHandles.constant(Double.class, Double.parseDouble(ctx.getText())) + ); + } + + @Override + public MethodHandle visitIdExpr(ExpressionParser.IdExprContext ctx) { + Token source = ctx.source; + return ExpressionHandles.call(data -> ExpressionHandles.getSlotValue(data, source)); + } + + /** + * Method handle (ExecutionData)Double, returns null. + */ + private static final MethodHandle DEFAULT_RESULT = + ExpressionHandles.dropData(MethodHandles.constant(Double.class, null)); + + @Override + protected MethodHandle defaultResult() { + return DEFAULT_RESULT; + } + + @Override + public MethodHandle visitChildren(RuleNode node) { + MethodHandle result = defaultResult(); + int n = node.getChildCount(); + for (int i = 0; i < n; i++) { + ParseTree c = node.getChild(i); + if (c instanceof TerminalNode && ((TerminalNode) c).getSymbol().getType() == Token.EOF) { + break; + } + + MethodHandle childResult = c.accept(this); + if (c instanceof ParserRuleContext) { + checkHandle(childResult, (ParserRuleContext) c); + } + + result = aggregateHandleResult(result, childResult); + } + + return result; + } + + @Override + protected MethodHandle aggregateResult(MethodHandle aggregate, MethodHandle nextResult) { + throw new UnsupportedOperationException(); + } + + private MethodHandle aggregateHandleResult(MethodHandle oldResult, MethodHandle result) { + // MH:oldResult,result = (ExecutionData)Double + + // Execute `oldResult` but ignore its return value, then execute result and return that. + // If either result is `defaultResult`, it's bogus, so just skip it + if (oldResult == DEFAULT_RESULT) { + return result; + } + if (result == DEFAULT_RESULT) { + return oldResult; + } + // Add a dummy Double parameter to the end + // MH:dummyDouble = (ExecutionData, Double)Double + MethodHandle dummyDouble = MethodHandles.dropArguments( + result, 1, Double.class + ); + // Have oldResult turn it from data->Double + // MH:doubledData = (ExecutionData, ExecutionData)Double + MethodHandle doubledData = MethodHandles.collectArguments( + dummyDouble, 1, oldResult + ); + // Deduplicate the `data` parameter + // MH:@return = (ExecutionData)Double + return ExpressionHandles.dedupData(doubledData); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java new file mode 100644 index 0000000..806d0c9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java @@ -0,0 +1,34 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression.invoke; + +import org.antlr.v4.runtime.ParserRuleContext; + +import java.lang.invoke.MethodHandle; + +class ExecNode { + final ParserRuleContext ctx; + final MethodHandle handle; + + ExecNode(ParserRuleContext ctx, MethodHandle handle) { + this.ctx = ctx; + this.handle = handle; + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionCompiler.java b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionCompiler.java new file mode 100644 index 0000000..dc0a052 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionCompiler.java @@ -0,0 +1,76 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression.invoke; + +import com.sk89q.worldedit.antlr.ExpressionParser; +import com.sk89q.worldedit.internal.expression.CompiledExpression; +import com.sk89q.worldedit.internal.expression.Functions; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodType.methodType; + +/** + * Compiles an expression from an AST into {@link MethodHandle}s. + */ +public class ExpressionCompiler { + + private static final String CE_EXECUTE = "execute"; + private static final MethodType HANDLE_TO_CE = + methodType(CompiledExpression.class, MethodHandle.class); + + private static final MethodHandle HANDLE_TO_CE_CONVERTER; + + static { + MethodHandle handleInvoker = MethodHandles.invoker(ExpressionHandles.COMPILED_EXPRESSION_SIG); + try { + HANDLE_TO_CE_CONVERTER = LambdaMetafactory.metafactory( + MethodHandles.lookup(), + // Implementing CompiledExpression.execute + CE_EXECUTE, + // Take a handle, to be converted to CompiledExpression + HANDLE_TO_CE, + // Raw signature for SAM type + ExpressionHandles.COMPILED_EXPRESSION_SIG, + // Handle to call the captured handle. + handleInvoker, + // Actual signature at invoke time + ExpressionHandles.COMPILED_EXPRESSION_SIG + ).dynamicInvoker().asType(HANDLE_TO_CE); + } catch (LambdaConversionException e) { + throw new IllegalStateException("Failed to load ExpressionCompiler MetaFactory", e); + } + } + + public CompiledExpression compileExpression(ExpressionParser.AllStatementsContext root, + Functions functions) { + MethodHandle invokable = root.accept(new CompilingVisitor(functions)); + // catch ReturnExpression and substitute its result + invokable = MethodHandles.catchException( + invokable, + ReturnException.class, + ExpressionHandles.RETURN_EXCEPTION_GET_RESULT + ); + MethodHandle finalInvokable = invokable; + return (CompiledExpression) ExpressionHandles.safeInvoke( + HANDLE_TO_CE_CONVERTER, h -> h.invoke(finalInvokable) + ); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java new file mode 100644 index 0000000..d23f207 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java @@ -0,0 +1,383 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression.invoke; + +import com.google.common.base.Throwables; +import com.sk89q.worldedit.internal.expression.*; +import it.unimi.dsi.fastutil.doubles.Double2ObjectMap; +import it.unimi.dsi.fastutil.doubles.Double2ObjectMaps; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; + +import javax.annotation.Nullable; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Objects; +import java.util.function.DoubleBinaryOperator; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.*; +import static java.lang.invoke.MethodHandles.*; +import static java.lang.invoke.MethodType.methodType; + +class ExpressionHandles { + + static final MethodType COMPILED_EXPRESSION_SIG = methodType(Double.class, ExecutionData.class); + + private static final MethodHandle EVAL_EXCEPTION_CONSTR; + private static final MethodHandle CALL_EXPRESSION; + private static final MethodHandle GET_VARIABLE; + private static final MethodHandle WHILE_FOR_LOOP_IMPL; + private static final MethodHandle DO_WHILE_LOOP_IMPL; + private static final MethodHandle SIMPLE_FOR_LOOP_IMPL; + private static final MethodHandle SWITCH_IMPL; + + // (Object)boolean; + static final MethodHandle IS_NULL; + // (Double)boolean; + static final MethodHandle DOUBLE_TO_BOOL; + // (double, double)Double; + static final MethodHandle CALL_BINARY_OP; + static final MethodHandle NEW_LS_CONSTANT; + // (Double)ReturnException; + static final MethodHandle NEW_RETURN_EXCEPTION; + // (ReturnException)Double; + static final MethodHandle RETURN_EXCEPTION_GET_RESULT; + + static final MethodHandle NULL_DOUBLE = dropData(constant(Double.class, null)); + + static { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + try { + EVAL_EXCEPTION_CONSTR = lookup.findConstructor( + EvaluationException.class, methodType(void.class, int.class, String.class)); + CALL_EXPRESSION = lookup.findVirtual( + CompiledExpression.class, "execute", + methodType(Double.class, ExecutionData.class)); + GET_VARIABLE = lookup.findStatic(ExpressionHandles.class, "getVariable", + methodType(LocalSlot.Variable.class, ExecutionData.class, Token.class)); + WHILE_FOR_LOOP_IMPL = lookup.findStatic(ExpressionHandles.class, + "whileForLoopImpl", + methodType(Double.class, ExecutionData.class, MethodHandle.class, + MethodHandle.class, ExecNode.class, MethodHandle.class)); + DO_WHILE_LOOP_IMPL = lookup.findStatic(ExpressionHandles.class, "doWhileLoopImpl", + methodType(Double.class, ExecutionData.class, MethodHandle.class, ExecNode.class)); + SIMPLE_FOR_LOOP_IMPL = lookup.findStatic(ExpressionHandles.class, "simpleForLoopImpl", + methodType(Double.class, ExecutionData.class, MethodHandle.class, + MethodHandle.class, Token.class, ExecNode.class)); + SWITCH_IMPL = lookup.findStatic(ExpressionHandles.class, "switchImpl", + methodType(Double.class, ExecutionData.class, Double2ObjectMap.class, + MethodHandle.class, ExecNode.class)); + + IS_NULL = lookup.findStatic(Objects.class, "isNull", + methodType(boolean.class, Object.class)); + DOUBLE_TO_BOOL = boxDoubles(lookup.findStatic(ExpressionHandles.class, "doubleToBool", + methodType(boolean.class, double.class))); + CALL_BINARY_OP = lookup.findVirtual(DoubleBinaryOperator.class, "applyAsDouble", + methodType(double.class, double.class, double.class)) + .asType(methodType(Double.class, DoubleBinaryOperator.class, double.class, double.class)); + NEW_LS_CONSTANT = lookup.findConstructor(LocalSlot.Constant.class, + methodType(void.class, double.class)); + NEW_RETURN_EXCEPTION = lookup.findConstructor(ReturnException.class, + methodType(void.class, Double.class)); + RETURN_EXCEPTION_GET_RESULT = lookup.findVirtual(ReturnException.class, + "getResult", methodType(Double.class)); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + + static MethodHandle boxDoubles(MethodHandle handle) { + MethodType type = handle.type(); + type = methodType( + boxIfPrimitiveDouble(type.returnType()), + type.parameterList().stream().map(ExpressionHandles::boxIfPrimitiveDouble) + .collect(Collectors.toList()) + ); + return handle.asType(type); + } + + private static Class boxIfPrimitiveDouble(Class clazz) { + return clazz == double.class ? Double.class : clazz; + } + + static MethodHandle unboxDoubles(MethodHandle handle) { + MethodType type = handle.type(); + type = methodType( + unboxIfDouble(type.returnType()), + type.parameterList().stream().map(ExpressionHandles::unboxIfDouble) + .collect(Collectors.toList()) + ); + return handle.asType(type); + } + + private static Class unboxIfDouble(Class clazz) { + return clazz == Double.class ? double.class : clazz; + } + + @FunctionalInterface + interface Invokable { + Object invoke(MethodHandle handle) throws Throwable; + } + + static Object safeInvoke(MethodHandle handle, Invokable invokable) { + try { + return invokable.invoke(handle); + } catch (Throwable t) { + Throwables.throwIfUnchecked(t); + throw new RuntimeException(t); + } + } + + static Object standardInvoke(MethodHandle handle, ExecutionData data) { + return safeInvoke(handle, h -> h.invoke(data)); + } + + static Object constantInvoke(MethodHandle handle) { + return standardInvoke(handle, ExecutionData.CONSTANT_EVALUATOR); + } + + static MethodHandle dropData(MethodHandle handle) { + return dropArguments(handle, 0, ExecutionData.class); + } + + static MethodHandle dedupData(MethodHandle doubleData) { + return permuteArguments( + doubleData, COMPILED_EXPRESSION_SIG, + 0, 0 + ); + } + + static LocalSlot.Variable initVariable(ExecutionData data, Token nameToken) { + String name = nameToken.getText(); + return data.getSlots().initVariable(name) + .orElseThrow(() -> ExpressionHelper.evalException( + nameToken, "Cannot overwrite non-variable '" + name + "'" + )); + } + + private static Supplier varNotInitException(Token nameToken) { + return () -> ExpressionHelper.evalException( + nameToken, "'" + nameToken.getText() + "' is not initialized yet" + ); + } + + static MethodHandle mhGetVariable(Token nameToken) { + return insertArguments(GET_VARIABLE, 1, nameToken); + } + + static LocalSlot.Variable getVariable(ExecutionData data, Token nameToken) { + String name = nameToken.getText(); + LocalSlot slot = data.getSlots().getSlot(name) + .orElseThrow(varNotInitException(nameToken)); + if (!(slot instanceof LocalSlot.Variable)) { + throw ExpressionHelper.evalException( + nameToken, "'" + name + "' is not a variable" + ); + } + return (LocalSlot.Variable) slot; + } + + static double getSlotValue(ExecutionData data, Token nameToken) { + String name = nameToken.getText(); + return data.getSlots().getSlotValue(name) + .orElseThrow(varNotInitException(nameToken)); + } + + /** + * Returns a method handle that calls + * {@link EvaluationException#EvaluationException(int, String)} with the supplied arguments. + */ + private static MethodHandle evalException(ParserRuleContext ctx, String message) { + return insertArguments(EVAL_EXCEPTION_CONSTR, 0, + getErrorPosition(ctx.start), message); + } + + /** + * Returns a method handle that takes no arguments, and throws the result of + * {@link #evalException(ParserRuleContext, String)}. It will additionally return Double. + */ + static MethodHandle throwEvalException(ParserRuleContext ctx, String message) { + // replace arg0 of `throw` with `evalException` + return collectArguments( + throwException(Double.class, EvaluationException.class), + 0, + evalException(ctx, message) + ); + } + + private static boolean doubleToBool(double bool) { + return bool != 0; + } + + static double boolToDouble(boolean bool) { + return bool ? 1 : 0; + } + + /** + * Encapsulate the given code into a MethodHandle. + */ + static MethodHandle call(CompiledExpression runnable) { + return CALL_EXPRESSION.bindTo(runnable).asType(COMPILED_EXPRESSION_SIG); + } + + static MethodHandle whileLoop(MethodHandle condition, ExecNode body) { + return insertArguments(WHILE_FOR_LOOP_IMPL, 1, + null, condition, body, null); + } + + static MethodHandle forLoop(MethodHandle init, + MethodHandle condition, + ExecNode body, + MethodHandle update) { + return insertArguments(WHILE_FOR_LOOP_IMPL, 1, + init, condition, body, update); + } + + private static Double whileForLoopImpl(ExecutionData data, + @Nullable MethodHandle init, + MethodHandle condition, + ExecNode body, + @Nullable MethodHandle update) { + Double result = null; + int iterations = 0; + if (init != null) { + standardInvoke(init, data); + } + while ((boolean) standardInvoke(condition, data)) { + checkIterations(iterations, body.ctx); + data.checkDeadline(); + iterations++; + try { + result = (Double) standardInvoke(body.handle, data); + } catch (BreakException ex) { + if (!ex.doContinue) { + break; + } + } + if (update != null) { + standardInvoke(update, data); + } + } + return result; + } + + static MethodHandle doWhileLoop(MethodHandle condition, ExecNode body) { + return insertArguments(DO_WHILE_LOOP_IMPL, 1, condition, body); + } + + private static Double doWhileLoopImpl(ExecutionData data, + MethodHandle condition, + ExecNode body) { + Double result = null; + int iterations = 0; + do { + checkIterations(iterations, body.ctx); + data.checkDeadline(); + iterations++; + try { + result = (Double) standardInvoke(body.handle, data); + } catch (BreakException ex) { + if (!ex.doContinue) { + break; + } + } + } while ((boolean) standardInvoke(condition, data)); + return result; + } + + static MethodHandle simpleForLoop(MethodHandle first, + MethodHandle last, + Token counter, + ExecNode body) { + return insertArguments(SIMPLE_FOR_LOOP_IMPL, 1, + first, last, counter, body); + } + + private static Double simpleForLoopImpl(ExecutionData data, + MethodHandle getFirst, + MethodHandle getLast, + Token counterToken, + ExecNode body) { + Double result = null; + int iterations = 0; + double first = (double) standardInvoke(getFirst, data); + double last = (double) standardInvoke(getLast, data); + LocalSlot.Variable variable = initVariable(data, counterToken); + for (double i = first; i <= last; i++) { + checkIterations(iterations, body.ctx); + data.checkDeadline(); + iterations++; + variable.setValue(i); + try { + result = (Double) standardInvoke(body.handle, data); + } catch (BreakException ex) { + if (!ex.doContinue) { + break; + } + } + } + return result; + } + + static MethodHandle switchStatement(Double2ObjectMap cases, + MethodHandle getValue, + @Nullable ExecNode defaultCase) { + return insertArguments(SWITCH_IMPL, 1, cases, getValue, defaultCase); + } + + private static Double switchImpl(ExecutionData data, + Double2ObjectMap cases, + MethodHandle getValue, + @Nullable ExecNode defaultCase) { + double value = (double) standardInvoke(getValue, data); + boolean matched = false; + Double evaluated = null; + boolean falling = false; + for (Double2ObjectMap.Entry entry : Double2ObjectMaps.fastIterable(cases)) { + if (falling || entry.getDoubleKey() == value) { + matched = true; + try { + evaluated = (Double) standardInvoke(entry.getValue().handle, data); + falling = true; + } catch (BreakException brk) { + check(!brk.doContinue, entry.getValue().ctx, "Cannot continue in a switch"); + falling = false; + break; + } + } + } + // This if is like the one in the loop, default's "case" is `!matched` & present + if ((falling || !matched) && defaultCase != null) { + try { + evaluated = (Double) standardInvoke(defaultCase.handle, data); + } catch (BreakException brk) { + check(!brk.doContinue, defaultCase.ctx, "Cannot continue in a switch"); + } + } + return evaluated; + } + + private ExpressionHandles() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ReturnException.java b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ReturnException.java new file mode 100644 index 0000000..7177105 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ReturnException.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.expression.invoke; + +/** + * Thrown when a return is encountered, to pop the stack frames and return the value easily. + * + *

+ * Should be caught by the executor. + *

+ */ +public class ReturnException extends RuntimeException { + + private final Double result; + + public ReturnException(Double result) { + super("return " + result, null, true, false); + this.result = result; + } + + public Double getResult() { + return result; + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java b/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java new file mode 100644 index 0000000..21455bd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java @@ -0,0 +1,191 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.helper; + +import com.sk89q.worldedit.util.Direction; + +/** + * Utility methods for working with directions in Minecraft. + */ +public final class MCDirections { + + private MCDirections() { + } + + public static Direction fromHanging(int i) { + switch (i) { + case 0: + return Direction.DOWN; + case 1: + return Direction.UP; + case 2: + return Direction.NORTH; + case 3: + return Direction.SOUTH; + case 4: + return Direction.WEST; + case 5: + return Direction.EAST; + default: + return Direction.DOWN; + } + } + + public static int toHanging(Direction direction) { + switch (direction) { + case DOWN: + return 0; + case UP: + return 1; + case NORTH: + return 2; + case SOUTH: + return 3; + case WEST: + return 4; + case EAST: + return 5; + default: + return 0; + } + } + + public static Direction fromPre13Hanging(int i) { + return fromHorizontalHanging(i); + } + + public static Direction fromHorizontalHanging(int i) { + switch (i) { + case 0: + return Direction.SOUTH; + case 1: + return Direction.WEST; + case 2: + return Direction.NORTH; + case 3: + return Direction.EAST; + default: + return Direction.NORTH; + } + } + + public static int toHorizontalHanging(Direction direction) { + switch (direction) { + case SOUTH: + return 0; + case WEST: + return 1; + case NORTH: + return 2; + case EAST: + return 3; + default: + return 0; + } + } + + public static int fromLegacyHanging(byte i) { + switch (i) { + case 0: return 2; + case 1: return 1; + case 2: return 0; + default: return 3; + } + } + + public static Direction fromRotation(int i) { + switch (i) { + case 0: + return Direction.SOUTH; + case 1: + return Direction.SOUTH_SOUTHWEST; + case 2: + return Direction.SOUTHWEST; + case 3: + return Direction.WEST_SOUTHWEST; + case 4: + return Direction.WEST; + case 5: + return Direction.WEST_NORTHWEST; + case 6: + return Direction.NORTHWEST; + case 7: + return Direction.NORTH_NORTHWEST; + case 8: + return Direction.NORTH; + case 9: + return Direction.NORTH_NORTHEAST; + case 10: + return Direction.NORTHEAST; + case 11: + return Direction.EAST_NORTHEAST; + case 12: + return Direction.EAST; + case 13: + return Direction.EAST_SOUTHEAST; + case 14: + return Direction.SOUTHEAST; + case 15: + return Direction.SOUTH_SOUTHEAST; + default: + return Direction.NORTH; + } + } + + public static int toRotation(Direction direction) { + switch (direction) { + case SOUTH: + return 0; + case SOUTH_SOUTHWEST: + return 1; + case SOUTHWEST: + return 2; + case WEST_SOUTHWEST: + return 3; + case WEST: + return 4; + case WEST_NORTHWEST: + return 5; + case NORTHWEST: + return 6; + case NORTH_NORTHWEST: + return 7; + case NORTH: + return 8; + case NORTH_NORTHEAST: + return 9; + case NORTHEAST: + return 10; + case EAST_NORTHEAST: + return 11; + case EAST: + return 12; + case EAST_SOUTHEAST: + return 13; + case SOUTHEAST: + return 14; + case SOUTH_SOUTHEAST: + return 15; + default: + return 0; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java new file mode 100644 index 0000000..c1d1ce5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -0,0 +1,103 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.registry; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An abstract implementation of a factory for internal usage. + * + * @param the element that the factory returns + */ +@SuppressWarnings("ProtectedField") +public abstract class AbstractFactory { + + protected final WorldEdit worldEdit; + private final List> parsers = new ArrayList<>(); + + /** + * Create a new factory. + * + * @param worldEdit the WorldEdit instance + * @param defaultParser the parser to fall back to + */ + protected AbstractFactory(WorldEdit worldEdit, InputParser defaultParser) { + checkNotNull(worldEdit); + checkNotNull(defaultParser); + this.worldEdit = worldEdit; + this.parsers.add(defaultParser); + } + + /** + * Gets an immutable list of parsers. + * + *

+ * To add parsers, use the register method. + *

+ * + * @return the parsers + */ + public List> getParsers() { + return Collections.unmodifiableList(parsers); + } + + public E parseFromInput(String input, ParserContext context) throws InputParseException { + E match; + + for (InputParser parser : parsers) { + match = parser.parseFromInput(input, context); + + if (match != null) { + return match; + } + } + + throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(input))); + } + + public List getSuggestions(String input) { + return parsers.stream().flatMap( + p -> p.getSuggestions(input) + ).collect(Collectors.toList()); + } + + /** + * Registers an InputParser to this factory. + * + * @param inputParser The input parser + */ + public void register(InputParser inputParser) { + checkNotNull(inputParser); + + parsers.add(parsers.size() - 1, inputParser); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java b/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java new file mode 100644 index 0000000..aff1973 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.registry; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; + +import java.util.stream.Stream; + +/** + * Input parser interface for {@link AbstractFactory}. + * + * @param the element + */ +@SuppressWarnings("ProtectedField") +public abstract class InputParser { + + protected final WorldEdit worldEdit; + + protected InputParser(WorldEdit worldEdit) { + this.worldEdit = worldEdit; + } + + public abstract E parseFromInput(String input, ParserContext context) throws InputParseException; + + /** + * Gets a stream of suggestions of input to this parser. + * + * @return a stream of suggestions + */ + public Stream getSuggestions(String input) { + return Stream.empty(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java b/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java new file mode 100644 index 0000000..faf9b34 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.registry; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; + +import java.util.List; +import java.util.Locale; +import java.util.stream.Stream; + +/** + * An input parser that only performs a single function from aliases. + * + * @param the element + */ +public abstract class SimpleInputParser extends InputParser { + + protected SimpleInputParser(WorldEdit worldEdit) { + super(worldEdit); + } + + /** + * The strings this parser matches. + * + * @return the matching aliases + */ + public abstract List getMatchedAliases(); + + @Override + public E parseFromInput(String input, ParserContext context) throws InputParseException { + if (!getMatchedAliases().contains(input)) { + return null; + } + + return parseFromSimpleInput(input, context); + } + + public abstract E parseFromSimpleInput(String input, ParserContext context) throws InputParseException; + + /** + * Gets the primary name of this matcher. + * + * @return the primary match + */ + public String getPrimaryMatcher() { + return getMatchedAliases().get(0); + } + + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of(getPrimaryMatcher()); + } + final String prefix = input.toLowerCase(Locale.ROOT); + for (String alias : getMatchedAliases()) { + if (alias.startsWith(prefix)) { + return Stream.of(alias); + } + } + return Stream.empty(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/util/AbstractAdapter.java b/src/main/java/com/sk89q/worldedit/internal/util/AbstractAdapter.java new file mode 100644 index 0000000..3118704 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/util/AbstractAdapter.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.util; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstract class for adapters. + * + * @param class of adapted objects + */ +public abstract class AbstractAdapter { + + private final E object; + + /** + * Create a new instance. + * + * @param object the object to adapt + */ + public AbstractAdapter(E object) { + checkNotNull(object); + this.object = object; + } + + /** + * Get the object. + * + * @return the object + */ + public E getHandle() { + return object; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/util/BiomeMath.java b/src/main/java/com/sk89q/worldedit/internal/util/BiomeMath.java new file mode 100644 index 0000000..595eab7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/util/BiomeMath.java @@ -0,0 +1,51 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.util; + +import net.royawesome.jlibnoise.MathHelper; + +public class BiomeMath { + + // From BiomeArray / BiomeContainer + public static final int HORIZONTAL_SECTION_COUNT = (int) Math.round(Math.log(16.0D) / Math.log(2.0D)) - 2; + public static final int HORIZONTAL_BIT_MASK = (1 << HORIZONTAL_SECTION_COUNT) - 1; + + private BiomeMath() { + } + + /** + * Compute the index into the MC biome array, for extended-height worlds. + * + * @param x the block x coordinate + * @param y the block y coordinate + * @param z the block z coordinate + * @param minY minimum y of the world + * @param maxY maximum y of the world + * @return the index into the standard MC biome array + */ + public static int computeBiomeIndex(int x, int y, int z, int minY, int maxY) { + int l = (x >> 2) & HORIZONTAL_BIT_MASK; + int m = MathHelper.clamp((y >> 2) - minY, 0, maxY); + int n = (z >> 2) & HORIZONTAL_BIT_MASK; + return m << HORIZONTAL_SECTION_COUNT + HORIZONTAL_SECTION_COUNT + | n << HORIZONTAL_SECTION_COUNT + | l; + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/util/DeprecationUtil.java b/src/main/java/com/sk89q/worldedit/internal/util/DeprecationUtil.java new file mode 100644 index 0000000..298cedb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/util/DeprecationUtil.java @@ -0,0 +1,118 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.util; + +import com.google.common.base.Joiner; +import com.google.common.base.Throwables; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.world.block.BlockCategories; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.lang.reflect.Method; +import java.util.stream.Stream; + +public class DeprecationUtil { + + private DeprecationUtil() { + } + + /** + * Verify that one of the two functions is overridden. Caller method must be the new method, + * annotated with {@link NonAbstractForCompatibility}. + * + * @param implementingClass the result of calling {@link Object#getClass()} + */ + public static void checkDelegatingOverride(Class implementingClass) { + // pull the information about the caller + StackTraceElement caller = Throwables.lazyStackTrace(new Throwable()).get(1); + // find the matching caller method + Method callingMethod = getCallingMethod(caller); + NonAbstractForCompatibility annotation = + callingMethod.getAnnotation(NonAbstractForCompatibility.class); + // get the deprecated method + Method deprecatedMethod; + try { + deprecatedMethod = implementingClass.getMethod( + annotation.delegateName(), annotation.delegateParams() + ); + } catch (NoSuchMethodException e) { + throw new AssertionError( + "Missing method referenced by " + NonAbstractForCompatibility.class, e + ); + } + // Check if the deprecated method was overridden. If the declaring class is the caller's + // class, then it wasn't. That means that the caller method (i.e. the new method) should be + // overridden by the implementing class. + // There's no need to check if the new method has been overridden, since the only other + // way this could be reached is if someone calls `super.xyz`, which they have no reason to. + if (deprecatedMethod.getDeclaringClass().getName().equals(caller.getClassName())) { + throw new IllegalStateException("Class " + implementingClass.getName() + + " must override " + methodToString(callingMethod)); + } + } + + private static Method getCallingMethod(StackTraceElement callerInfo) { + Method[] declaredMethods; + try { + declaredMethods = Class.forName(callerInfo.getClassName()).getDeclaredMethods(); + } catch (ClassNotFoundException e) { + throw new AssertionError("Caller class missing?", e); + } + for (Method declaredMethod : declaredMethods) { + if (declaredMethod.isAnnotationPresent(NonAbstractForCompatibility.class) + && declaredMethod.getName().equals(callerInfo.getMethodName())) { + return declaredMethod; + } + } + throw new IllegalStateException("Failed to find caller method " + + callerInfo.getMethodName() + " annotated with " + NonAbstractForCompatibility.class); + } + + private static String methodToString(Method method) { + StringBuilder builder = new StringBuilder(method.getDeclaringClass().getCanonicalName()) + .append('.') + .append(method.getName()) + .append('('); + Joiner.on(", ").appendTo(builder, Stream.of(method.getParameterTypes()) + .map(Class::getSimpleName) + .iterator()); + builder.append(')'); + return builder.toString(); + } + + public static boolean isSign(BlockType blockType) { + @SuppressWarnings("deprecation") + BlockType sign = BlockTypes.SIGN; + @SuppressWarnings("deprecation") + BlockType wallSign = BlockTypes.WALL_SIGN; + return blockType == sign || blockType == wallSign + || BlockCategories.SIGNS.contains(blockType); + } + + public static String getHeadOwnerKey() { + int dataVersion = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getDataVersion(); + return dataVersion >= Constants.DATA_VERSION_MC_1_16 ? "SkullOwner" : "Owner"; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/util/InfoEntryPoint.java b/src/main/java/com/sk89q/worldedit/internal/util/InfoEntryPoint.java new file mode 100644 index 0000000..e5d18e1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/util/InfoEntryPoint.java @@ -0,0 +1,88 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.util; + +import com.sk89q.worldedit.WorldEditManifest; + +import javax.swing.*; +import javax.swing.event.HyperlinkEvent; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.HTMLEditorKit; +import java.awt.*; +import java.io.IOException; +import java.net.URISyntaxException; + +public class InfoEntryPoint { + + private static final String INSTALL_URL = "https://worldedit.enginehub.org/en/latest/install/"; + private static final String SUPPORT_URL = "https://discord.gg/enginehub"; + + private static String getMessage(boolean html) { + WorldEditManifest manifest = WorldEditManifest.load(); + + return "To install WorldEdit, place it in the " + + manifest.getWorldEditKind().folderName + " folder.\n" + + "For more detailed instructions, see " + formatLink(INSTALL_URL, html) + "\n" + + "For further help, check out our support Discord at " + + formatLink(SUPPORT_URL, html) + "\n" + + "\n" + + "Version: " + manifest.getWorldEditVersion() + "\n"; + } + + private static String formatLink(String url, boolean html) { + return html ? String.format("%1$s", url) : url; + } + + public static void main(String[] args) { + if (System.console() != null) { + System.err.println(getMessage(false)); + } else { + System.setProperty("awt.useSystemAAFontSettings", "lcd"); + JOptionPane.showMessageDialog( + null, + new NavigableEditorPane(getMessage(true)), + "WorldEdit", + JOptionPane.INFORMATION_MESSAGE + ); + } + System.exit(1); + } + + private static class NavigableEditorPane extends JTextPane { + public NavigableEditorPane(String htmlBody) { + super(new HTMLDocument()); + setEditorKit(new HTMLEditorKit()); + setText(htmlBody.replace("\n", "
")); + setBackground(UIManager.getColor("Panel.background")); + + addHyperlinkListener(e -> { + if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { + try { + Desktop.getDesktop().browse(e.getURL().toURI()); + } catch (IOException | URISyntaxException ex) { + ex.printStackTrace(); + } + } + }); + setEditable(false); + setBorder(null); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/util/LogManagerCompat.java b/src/main/java/com/sk89q/worldedit/internal/util/LogManagerCompat.java new file mode 100644 index 0000000..e2a80b4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/util/LogManagerCompat.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.util; + +import com.google.common.base.Throwables; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +public class LogManagerCompat { + + public static Logger getLogger() { + return LogManager.getLogger(getCallerCallerClassName()); + } + + private static String getCallerCallerClassName() { + List lazyStack = Throwables.lazyStackTrace(new Throwable()); + // 0 - this method + // 1 - caller + // 2 - caller caller + return lazyStack.get(2).getClassName(); + } + + private LogManagerCompat() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/util/NonAbstractForCompatibility.java b/src/main/java/com/sk89q/worldedit/internal/util/NonAbstractForCompatibility.java new file mode 100644 index 0000000..95d7c23 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/util/NonAbstractForCompatibility.java @@ -0,0 +1,57 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.util; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The annotated method is only non-{@code abstract} for compatibility with old subclasses, + * and will be made {@code abstract} in the next major version of WorldEdit. + * + *

+ * Any new subclasses must override the annotated method, failing to do so will result in + * an exception at runtime. + *

+ */ +@Documented +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface NonAbstractForCompatibility { + + // Note that this annotation only functions properly if no other method in the same class + // shares the name of the annotated function AND is also annotated with this annotation. + // Otherwise, we cannot uniquely determine the calling method via reflection hacks. + // This could be changed, but it's not currently necessary. + + /** + * The name of the method delegated to by the annotated method. + */ + String delegateName(); + + /** + * The parameter types of the method delegated to by the annotated method. + */ + Class[] delegateParams(); + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorter.java b/src/main/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorter.java new file mode 100644 index 0000000..3bb4ebc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorter.java @@ -0,0 +1,216 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.util; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.sk89q.worldedit.math.BlockVector3; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.ListIterator; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import static com.sk89q.worldedit.math.BitMath.mask; + +/** + * Uses a radix sort to order vectors by region, then chunk, then Y value (max -> min). + */ +public class RegionOptimizedVectorSorter { + + // We need to sort by region file, chunk, and Y (x/z don't really matter) + // Due to MC having x/z axes of only 60,000,000 blocks, the max value is <=26 bits. + // We can store the chunk in 4 bits less, 22 bits; and region in 5 bits less than that, 17 bits + // If we share the region + chunk bits, we can make a radix key that is really 5 parts: + // [region X (17)][region Z (17)][chunk X (5)][chunk Z (5)][block Y (20)] = 64 bits + // Even though we only normally need 8 bits for Y, we might as well use it for cubic chunks + // compatibility in the future, since we have the room in the long value + private static final int CHUNK_Z_SHIFT = 20; + private static final int CHUNK_X_SHIFT = 5 + CHUNK_Z_SHIFT; + private static final int REGION_Z_SHIFT = 5 + CHUNK_X_SHIFT; + private static final int REGION_X_SHIFT = 17 + REGION_Z_SHIFT; + private static final long REGION_X_MASK = ((long) mask(17)) << REGION_X_SHIFT; + private static final long REGION_Z_MASK = ((long) mask(17)) << REGION_Z_SHIFT; + private static final long CHUNK_X_MASK = ((long) mask(5)) << CHUNK_X_SHIFT; + private static final long CHUNK_Z_MASK = ((long) mask(5)) << CHUNK_Z_SHIFT; + private static final int Y_MAX = mask(20); + // We flip the region x/z sign to turn signed numbers into unsigned ones + // this allows us to sort on the raw bits, and not care about signs + // Essentially it transforms [negative values][positive values] + // to [positive value][even more positive values], i.e. a shift upwards + private static final long FLIP_REGION_X_SIGN = 0x1_00_00L << REGION_X_SHIFT; + private static final long FLIP_REGION_Z_SIGN = 0x1_00_00L << REGION_Z_SHIFT; + + private static long key(BlockVector3 elem) { + long x = elem.getX(); + long z = elem.getZ(); + return (((x << (REGION_X_SHIFT - 9)) & REGION_X_MASK) ^ FLIP_REGION_X_SIGN) + | (((z << (REGION_Z_SHIFT - 9)) & REGION_Z_MASK) ^ FLIP_REGION_Z_SIGN) + | ((x << (CHUNK_X_SHIFT - 4)) & CHUNK_X_MASK) + | ((z << (CHUNK_Z_SHIFT - 4)) & CHUNK_Z_MASK) + | (Y_MAX - elem.getY()); + } + + private static final int NUMBER_OF_BITS = 64; + private static final int BITS_PER_SORT = 16; + private static final int MAX_FOR_BPS = 1 << BITS_PER_SORT; + private static final int MASK_FOR_BPS = (1 << BITS_PER_SORT) - 1; + private static final int NUMBER_OF_SORTS = NUMBER_OF_BITS / BITS_PER_SORT; + private static final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors(); + static int PARALLELISM_THRESHOLD; + + static { + if (NUMBER_OF_CORES == 1) { + // don't even bother + PARALLELISM_THRESHOLD = Integer.MAX_VALUE; + } else { + // Determined via benchmarking serial vs. parallel. + // Didn't try anything more fine-grained that increments of 100,000. + PARALLELISM_THRESHOLD = 200000; + } + } + + private static final ExecutorService SORT_SVC = Executors.newFixedThreadPool( + Runtime.getRuntime().availableProcessors(), + new ThreadFactoryBuilder() + .setDaemon(true) + .setNameFormat("worldedit-sort-svc-%d") + .build() + ); + + public static void sort(List vectors) { + sort(vectors.size() >= PARALLELISM_THRESHOLD, vectors); + } + + /** + * For test purposes, or if you want to finely control when parallelism occurs. + * + *

+ * {@code vectors} must be mutable, and will be sorted after this method returns. + *

+ * + * @param parallel {@code true} to sort in parallel + * @param vectors the vectors to sort + */ + public static void sort(boolean parallel, List vectors) { + // Currently we don't do an in-place radix sort, but we could in the future. + int size = vectors.size(); + // take care of some easy cases + if (size == 0 || size == 1) { + return; + } + BlockVector3[] source = vectors.toArray(new BlockVector3[0]); + BlockVector3[] sorted = new BlockVector3[size]; + source = !parallel + ? serialSort(source, size, sorted) + : parallelSort(source, size, sorted); + ListIterator it = vectors.listIterator(); + for (BlockVector3 blockVector3 : source) { + it.next(); + it.set(blockVector3); + } + } + + private static BlockVector3[] parallelSort(BlockVector3[] source, int size, BlockVector3[] sorted) { + int[][] counts = new int[NUMBER_OF_CORES][MAX_FOR_BPS]; + int[] finalCounts = new int[MAX_FOR_BPS]; + int[] keys = new int[size]; + List> tasks = new ArrayList<>(NUMBER_OF_CORES); + int kStep = (size + NUMBER_OF_CORES - 1) / NUMBER_OF_CORES; + for (int p = 0; p < NUMBER_OF_SORTS; p++) { + BlockVector3[] currentSource = source; + int shift = BITS_PER_SORT * p; + for (int c = 0; c < NUMBER_OF_CORES; c++) { + int[] localCounts = counts[c]; + int kStart = kStep * c; + int kEnd = Math.min(kStart + kStep, size); + tasks.add(SORT_SVC.submit(() -> { + for (int i = kStart; i < kEnd; i++) { + int k = ((int) (key(currentSource[i]) >>> shift) & MASK_FOR_BPS); + keys[i] = k; + localCounts[k]++; + } + return localCounts; + })); + } + for (Future task : tasks) { + try { + task.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(e); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + } + for (int c = 0; c < NUMBER_OF_CORES; c++) { + int[] localCounts = counts[c]; + for (int i = 0; i < MAX_FOR_BPS; i++) { + finalCounts[i] += localCounts[i]; + localCounts[i] = 0; + } + } + tasks.clear(); + copyByCounts(size, source, sorted, keys, finalCounts); + BlockVector3[] temp = source; + source = sorted; + sorted = temp; + } + // after the loop returns, source is now the final sorted array! + return source; + } + + private static BlockVector3[] serialSort(BlockVector3[] source, int size, BlockVector3[] sorted) { + int[] counts = new int[MAX_FOR_BPS]; + int[] keys = new int[size]; + for (int p = 0; p < NUMBER_OF_SORTS; p++) { + for (int i = 0; i < size; i++) { + int k = ((int) (key(source[i]) >>> (BITS_PER_SORT * p)) & MASK_FOR_BPS); + keys[i] = k; + counts[k]++; + } + copyByCounts(size, source, sorted, keys, counts); + BlockVector3[] temp = source; + source = sorted; + sorted = temp; + } + // after the loop returns, source is now the final sorted array! + return source; + } + + private static void copyByCounts(int size, BlockVector3[] source, BlockVector3[] sorted, int[] keys, int[] finalCounts) { + int lastCount = finalCounts[0]; + for (int i = 1; i < MAX_FOR_BPS; i++) { + lastCount = (finalCounts[i] += lastCount); + } + for (int i = size - 1; i >= 0; i--) { + int key = keys[i]; + int count = --finalCounts[key]; + sorted[count] = source[i]; + } + Arrays.fill(finalCounts, 0); + } + + private RegionOptimizedVectorSorter() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/util/Substring.java b/src/main/java/com/sk89q/worldedit/internal/util/Substring.java new file mode 100644 index 0000000..fd8514e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/util/Substring.java @@ -0,0 +1,105 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.util; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * An explicit substring. Provides the range from which it was taken. + */ +public final class Substring { + + /** + * Take a substring from {@code original}, and {@link #wrap(String, int, int)} it into + * a Substring. + */ + public static Substring from(String original, int start) { + return new Substring(original.substring(start), start, original.length()); + } + + /** + * Take a substring from {@code original}, and {@link #wrap(String, int, int)} it into + * a Substring. + */ + public static Substring from(String original, int start, int end) { + return new Substring(original.substring(start, end), start, end); + } + + /** + * Wrap the given parameters into a Substring instance. + */ + public static Substring wrap(String substring, int start, int end) { + checkArgument(0 <= start, "Start must be greater than or equal to zero"); + checkArgument(start <= end, "End must be greater than or equal to start"); + return new Substring(substring, start, end); + } + + private final String substring; + private final int start; + private final int end; + + private Substring(String substring, int start, int end) { + this.substring = substring; + this.start = start; + this.end = end; + } + + public String getSubstring() { + return substring; + } + + public int getStart() { + return start; + } + + public int getEnd() { + return end; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Substring substring1 = (Substring) o; + return start == substring1.start + && end == substring1.end + && substring.equals(substring1.substring); + } + + @Override + public int hashCode() { + return Objects.hash(substring, start, end); + } + + @Override + public String toString() { + return "Substring{" + + "substring='" + substring + "'" + + ",start=" + start + + ",end=" + end + + "}"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java b/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java new file mode 100644 index 0000000..7895edb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java @@ -0,0 +1,196 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.internal.wna; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Natively access and perform operations on the world. + * + * @param the native chunk type + * @param the native block state type + * @param the native position type + */ +public interface WorldNativeAccess { + + default > boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException { + checkNotNull(position); + checkNotNull(block); + setCurrentSideEffectSet(sideEffects); + + int x = position.getBlockX(); + int y = position.getBlockY(); + int z = position.getBlockZ(); + + // First set the block + NC chunk = getChunk(x >> 4, z >> 4); + NP pos = getPosition(x, y, z); + NBS old = getBlockState(chunk, pos); + NBS newState = toNative(block.toImmutableState()); + // change block prior to placing if it should be fixed + if (sideEffects.shouldApply(SideEffect.VALIDATION)) { + newState = getValidBlockForPosition(newState, pos); + } + NBS lastValue = setBlockState(chunk, pos, newState); + boolean successful = lastValue != null; + + // Create the TileEntity + if (successful || old == newState) { + if (block instanceof BaseBlock) { + BaseBlock baseBlock = (BaseBlock) block; + CompoundTag tag = baseBlock.getNbtData(); + if (tag != null) { + tag = tag.createBuilder() + .putString("id", baseBlock.getNbtId()) + .putInt("x", position.getX()) + .putInt("y", position.getY()) + .putInt("z", position.getZ()) + .build(); + // update if TE changed as well + successful = updateTileEntity(pos, tag); + } + } + } + + if (successful) { + if (sideEffects.getState(SideEffect.LIGHTING) == SideEffect.State.ON) { + updateLightingForBlock(pos); + } + markAndNotifyBlock(pos, chunk, old, newState, sideEffects); + } + + return successful; + } + + default void applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) { + setCurrentSideEffectSet(sideEffectSet); + NP pos = getPosition(position.getX(), position.getY(), position.getZ()); + NC chunk = getChunk(position.getX() >> 4, position.getZ() >> 4); + NBS oldData = toNative(previousType); + NBS newData = getBlockState(chunk, pos); + + if (sideEffectSet.shouldApply(SideEffect.UPDATE)) { + updateBlock(pos, oldData, newData); + } + + if (sideEffectSet.getState(SideEffect.LIGHTING) == SideEffect.State.ON) { + updateLightingForBlock(pos); + } + + markAndNotifyBlock(pos, chunk, oldData, newData, sideEffectSet); + } + + // state-keeping functions for WNA + // may be thread-unsafe, as this is single-threaded code + + /** + * Receive the current side-effect set from the high level call. + * + *

+ * This allows the implementation to branch on the side-effects internally. + *

+ * + * @param sideEffectSet the set of side-effects + */ + default void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + } + + // access functions + + NC getChunk(int x, int z); + + NBS toNative(BlockState state); + + NBS getBlockState(NC chunk, NP position); + + @Nullable + NBS setBlockState(NC chunk, NP position, NBS state); + + NBS getValidBlockForPosition(NBS block, NP position); + + NP getPosition(int x, int y, int z); + + void updateLightingForBlock(NP position); + + boolean updateTileEntity(NP position, CompoundTag tag); + + void notifyBlockUpdate(NC chunk, NP position, NBS oldState, NBS newState); + + boolean isChunkTicking(NC chunk); + + void markBlockChanged(NC chunk, NP position); + + void notifyNeighbors(NP pos, NBS oldState, NBS newState); + + default void updateBlock(NP pos, NBS oldState, NBS newState) { + } + + void updateNeighbors(NP pos, NBS oldState, NBS newState, int recursionLimit); + + void onBlockStateChange(NP pos, NBS oldState, NBS newState); + + /** + * This is a heavily modified function stripped from MC to apply WorldEdit-modifications. + * + *

+ * See Forge's World.markAndNotifyBlock + *

+ */ + default void markAndNotifyBlock(NP pos, NC chunk, NBS oldState, NBS newState, SideEffectSet sideEffectSet) { + NBS blockState1 = getBlockState(chunk, pos); + if (blockState1 != newState) { + return; + } + + // Remove redundant branches + if (isChunkTicking(chunk)) { + if (sideEffectSet.shouldApply(SideEffect.ENTITY_AI)) { + notifyBlockUpdate(chunk, pos, oldState, newState); + } else { + // If we want to skip entity AI, just mark the block for sending + markBlockChanged(chunk, pos); + } + } + + if (sideEffectSet.shouldApply(SideEffect.NEIGHBORS)) { + notifyNeighbors(pos, oldState, newState); + } + + // Make connection updates optional + if (sideEffectSet.shouldApply(SideEffect.NEIGHBORS)) { + updateNeighbors(pos, oldState, newState, 512); + } + + // Seems used only for PoI updates + onBlockStateChange(pos, oldState, blockState1); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/wna/package-info.java b/src/main/java/com/sk89q/worldedit/internal/wna/package-info.java new file mode 100644 index 0000000..182a404 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/wna/package-info.java @@ -0,0 +1,27 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +/** + * "WNA", or WorldEdit Native Access. + * + *

+ * Contains internal helper functions for sharing code between platforms. + *

+ */ +package com.sk89q.worldedit.internal.wna; diff --git a/src/main/java/com/sk89q/worldedit/math/BitMath.java b/src/main/java/com/sk89q/worldedit/math/BitMath.java new file mode 100644 index 0000000..8b67476 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/BitMath.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math; + +public final class BitMath { + + public static int mask(int bits) { + return ~(~0 << bits); + } + + public static int unpackX(long packed) { + return extractSigned(packed, 0, 26); + } + + public static int unpackZ(long packed) { + return extractSigned(packed, 26, 26); + } + + public static int unpackY(long packed) { + return extractSigned(packed, 26 + 26, 12); + } + + public static int extractSigned(long i, int shift, int bits) { + return fixSign((int) (i >> shift) & mask(bits), bits); + } + + public static int fixSign(int i, int bits) { + // Using https://stackoverflow.com/a/29266331/436524 + return i << (32 - bits) >> (32 - bits); + } + + private BitMath() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/BlockVector2.java b/src/main/java/com/sk89q/worldedit/math/BlockVector2.java new file mode 100644 index 0000000..aa020ce --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/BlockVector2.java @@ -0,0 +1,567 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math; + +import com.sk89q.worldedit.math.transform.AffineTransform; + +import java.util.Comparator; + +/** + * An immutable 2-dimensional vector. + */ +public final class BlockVector2 { + + public static final BlockVector2 ZERO = new BlockVector2(0, 0); + public static final BlockVector2 UNIT_X = new BlockVector2(1, 0); + public static final BlockVector2 UNIT_Z = new BlockVector2(0, 1); + public static final BlockVector2 ONE = new BlockVector2(1, 1); + + /** + * A comparator for BlockVector2ds that orders the vectors by rows, with x as the + * column and z as the row. + * + *

+ * For example, if x is the horizontal axis and z is the vertical axis, it + * sorts like so: + *

+ * + *
+     * 0123
+     * 4567
+     * 90ab
+     * cdef
+     * 
+ */ + public static final Comparator COMPARING_GRID_ARRANGEMENT = + Comparator.comparingInt(BlockVector2::getZ).thenComparingInt(BlockVector2::getX); + + public static BlockVector2 at(double x, double z) { + return at((int) Math.floor(x), (int) Math.floor(z)); + } + + public static BlockVector2 at(int x, int z) { + switch (x) { + case 0: + if (z == 0) { + return ZERO; + } + break; + case 1: + if (z == 1) { + return ONE; + } + break; + default: + break; + } + return new BlockVector2(x, z); + } + + private final int x; + private final int z; + + /** + * Construct an instance. + * + * @param x the X coordinate + * @param z the Z coordinate + */ + private BlockVector2(int x, int z) { + this.x = x; + this.z = z; + } + + /** + * Get the X coordinate. + * + * @return the x coordinate + */ + public int getX() { + return x; + } + + /** + * Get the X coordinate. + * + * @return the x coordinate + */ + public int getBlockX() { + return x; + } + + /** + * Set the X coordinate. + * + * @param x the new X + * @return a new vector + */ + public BlockVector2 withX(int x) { + return BlockVector2.at(x, z); + } + + /** + * Get the Z coordinate. + * + * @return the z coordinate + */ + public int getZ() { + return z; + } + + /** + * Get the Z coordinate. + * + * @return the z coordinate + */ + public int getBlockZ() { + return z; + } + + /** + * Set the Z coordinate. + * + * @param z the new Z + * @return a new vector + */ + public BlockVector2 withZ(int z) { + return BlockVector2.at(x, z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param other the other vector + * @return a new vector + */ + public BlockVector2 add(BlockVector2 other) { + return add(other.x, other.z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param x the value to add + * @param z the value to add + * @return a new vector + */ + public BlockVector2 add(int x, int z) { + return BlockVector2.at(this.x + x, this.z + z); + } + + /** + * Add a list of vectors to this vector and return the + * result as a new vector. + * + * @param others an array of vectors + * @return a new vector + */ + public BlockVector2 add(BlockVector2... others) { + int newX = x; + int newZ = z; + + for (BlockVector2 other : others) { + newX += other.x; + newZ += other.z; + } + + return BlockVector2.at(newX, newZ); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param other the other vector + * @return a new vector + */ + public BlockVector2 subtract(BlockVector2 other) { + return subtract(other.x, other.z); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param x the value to subtract + * @param z the value to subtract + * @return a new vector + */ + public BlockVector2 subtract(int x, int z) { + return BlockVector2.at(this.x - x, this.z - z); + } + + /** + * Subtract a list of vectors from this vector and return the result + * as a new vector. + * + * @param others an array of vectors + * @return a new vector + */ + public BlockVector2 subtract(BlockVector2... others) { + int newX = x; + int newZ = z; + + for (BlockVector2 other : others) { + newX -= other.x; + newZ -= other.z; + } + + return BlockVector2.at(newX, newZ); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param other the other vector + * @return a new vector + */ + public BlockVector2 multiply(BlockVector2 other) { + return multiply(other.x, other.z); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param x the value to multiply + * @param z the value to multiply + * @return a new vector + */ + public BlockVector2 multiply(int x, int z) { + return BlockVector2.at(this.x * x, this.z * z); + } + + /** + * Multiply this vector by zero or more vectors on each component. + * + * @param others an array of vectors + * @return a new vector + */ + public BlockVector2 multiply(BlockVector2... others) { + int newX = x; + int newZ = z; + + for (BlockVector2 other : others) { + newX *= other.x; + newZ *= other.z; + } + + return BlockVector2.at(newX, newZ); + } + + /** + * Perform scalar multiplication and return a new vector. + * + * @param n the value to multiply + * @return a new vector + */ + public BlockVector2 multiply(int n) { + return multiply(n, n); + } + + /** + * Divide this vector by another vector on each component. + * + * @param other the other vector + * @return a new vector + */ + public BlockVector2 divide(BlockVector2 other) { + return divide(other.x, other.z); + } + + /** + * Divide this vector by another vector on each component. + * + * @param x the value to divide by + * @param z the value to divide by + * @return a new vector + */ + public BlockVector2 divide(int x, int z) { + return BlockVector2.at(this.x / x, this.z / z); + } + + /** + * Perform scalar division and return a new vector. + * + * @param n the value to divide by + * @return a new vector + */ + public BlockVector2 divide(int n) { + return divide(n, n); + } + + /** + * Shift all components right. + * + * @param x the value to shift x by + * @param z the value to shift z by + * @return a new vector + */ + public BlockVector2 shr(int x, int z) { + return at(this.x >> x, this.z >> z); + } + + /** + * Shift all components right by {@code n}. + * + * @param n the value to shift by + * @return a new vector + */ + public BlockVector2 shr(int n) { + return shr(n, n); + } + + /** + * Get the length of the vector. + * + * @return length + */ + public double length() { + return Math.sqrt(lengthSq()); + } + + /** + * Get the length, squared, of the vector. + * + * @return length, squared + */ + public int lengthSq() { + return x * x + z * z; + } + + /** + * Get the distance between this vector and another vector. + * + * @param other the other vector + * @return distance + */ + public double distance(BlockVector2 other) { + return Math.sqrt(distanceSq(other)); + } + + /** + * Get the distance between this vector and another vector, squared. + * + * @param other the other vector + * @return distance + */ + public int distanceSq(BlockVector2 other) { + int dx = other.x - x; + int dz = other.z - z; + return dx * dx + dz * dz; + } + + /** + * Get the normalized vector, which is the vector divided by its + * length, as a new vector. + * + * @return a new vector + */ + public BlockVector2 normalize() { + double len = length(); + double x = this.x / len; + double z = this.z / len; + return BlockVector2.at(x, z); + } + + /** + * Gets the dot product of this and another vector. + * + * @param other the other vector + * @return the dot product of this and the other vector + */ + public int dot(BlockVector2 other) { + return x * other.x + z * other.z; + } + + /** + * Checks to see if a vector is contained with another. + * + * @param min the minimum point (X, Y, and Z are the lowest) + * @param max the maximum point (X, Y, and Z are the lowest) + * @return true if the vector is contained + */ + public boolean containedWithin(BlockVector2 min, BlockVector2 max) { + return x >= min.x && x <= max.x + && z >= min.z && z <= max.z; + } + + /** + * Floors the values of all components. + * + * @return a new vector + */ + public BlockVector2 floor() { + // already floored, kept for feature parity with Vector2 + return this; + } + + /** + * Rounds all components up. + * + * @return a new vector + */ + public BlockVector2 ceil() { + // already raised, kept for feature parity with Vector2 + return this; + } + + /** + * Rounds all components to the closest integer. + * + *

Components < 0.5 are rounded down, otherwise up.

+ * + * @return a new vector + */ + public BlockVector2 round() { + // already rounded, kept for feature parity with Vector2 + return this; + } + + /** + * Returns a vector with the absolute values of the components of + * this vector. + * + * @return a new vector + */ + public BlockVector2 abs() { + return BlockVector2.at(Math.abs(x), Math.abs(z)); + } + + /** + * Perform a 2D transformation on this vector and return a new one. + * + * @param angle in degrees + * @param aboutX about which x coordinate to rotate + * @param aboutZ about which z coordinate to rotate + * @param translateX what to add after rotation + * @param translateZ what to add after rotation + * @return a new vector + * @see AffineTransform another method to transform vectors + */ + public BlockVector2 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { + angle = Math.toRadians(angle); + double x = this.x - aboutX; + double z = this.z - aboutZ; + double cos = Math.cos(angle); + double sin = Math.sin(angle); + double x2 = x * cos - z * sin; + double z2 = x * sin + z * cos; + return BlockVector2.at( + x2 + aboutX + translateX, + z2 + aboutZ + translateZ); + } + + /** + * Gets the minimum components of two vectors. + * + * @param v2 the second vector + * @return minimum + */ + public BlockVector2 getMinimum(BlockVector2 v2) { + return new BlockVector2( + Math.min(x, v2.x), + Math.min(z, v2.z) + ); + } + + /** + * Gets the maximum components of two vectors. + * + * @param v2 the second vector + * @return maximum + */ + public BlockVector2 getMaximum(BlockVector2 v2) { + return new BlockVector2( + Math.max(x, v2.x), + Math.max(z, v2.z) + ); + } + + public Vector2 toVector2() { + return Vector2.at(x, z); + } + + /** + * Creates a 3D vector by adding a zero Y component to this vector. + * + * @return a new vector + */ + public Vector3 toVector3() { + return toVector3(0); + } + + /** + * Creates a 3D vector by adding the specified Y component to this vector. + * + * @param y the Y component + * @return a new vector + */ + public Vector3 toVector3(double y) { + return Vector3.at(x, y, z); + } + + /** + * Creates a 3D vector by adding a zero Y component to this vector. + * + * @return a new vector + */ + public BlockVector3 toBlockVector3() { + return toBlockVector3(0); + } + + /** + * Creates a 3D vector by adding the specified Y component to this vector. + * + * @param y the Y component + * @return a new vector + */ + public BlockVector3 toBlockVector3(int y) { + return BlockVector3.at(x, y, z); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof BlockVector2)) { + return false; + } + + BlockVector2 other = (BlockVector2) obj; + return other.x == this.x && other.z == this.z; + + } + + @Override + public int hashCode() { + return (x << 16) ^ z; + } + + @Override + public String toString() { + return "(" + x + ", " + z + ")"; + } + + /** + * Returns a string representation that is supported by the parser. + * @return string + */ + public String toParserString() { + return x + "," + z; + } +} diff --git a/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/src/main/java/com/sk89q/worldedit/math/BlockVector3.java new file mode 100644 index 0000000..abb54e9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -0,0 +1,716 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math; + +import com.sk89q.worldedit.math.transform.AffineTransform; + +import java.util.Comparator; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.sk89q.worldedit.math.BitMath.mask; +import static com.sk89q.worldedit.math.BitMath.unpackX; +import static com.sk89q.worldedit.math.BitMath.unpackY; +import static com.sk89q.worldedit.math.BitMath.unpackZ; + +/** + * An immutable 3-dimensional vector. + */ +public final class BlockVector3 { + + public static final BlockVector3 ZERO = new BlockVector3(0, 0, 0); + public static final BlockVector3 UNIT_X = new BlockVector3(1, 0, 0); + public static final BlockVector3 UNIT_Y = new BlockVector3(0, 1, 0); + public static final BlockVector3 UNIT_Z = new BlockVector3(0, 0, 1); + public static final BlockVector3 UNIT_MINUS_X = new BlockVector3(-1, 0, 0); + public static final BlockVector3 UNIT_MINUS_Y = new BlockVector3(0, -1, 0); + public static final BlockVector3 UNIT_MINUS_Z = new BlockVector3(0, 0, -1); + public static final BlockVector3 ONE = new BlockVector3(1, 1, 1); + + public static BlockVector3 at(double x, double y, double z) { + return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); + } + + public static BlockVector3 at(int x, int y, int z) { + // switch for efficiency on typical cases + // in MC y is rarely 0/1 on selections + switch (y) { + case 0: + if (x == 0 && z == 0) { + return ZERO; + } + break; + case 1: + if (x == 1 && z == 1) { + return ONE; + } + break; + default: + break; + } + return new BlockVector3(x, y, z); + } + + private static final int WORLD_XZ_MINMAX = 30_000_000; + private static final int WORLD_Y_MIN = -2048; + private static final int WORLD_Y_MAX = 2047; + + private static boolean isHorizontallyInBounds(int h) { + return -WORLD_XZ_MINMAX <= h && h <= WORLD_XZ_MINMAX; + } + + public static boolean isLongPackable(BlockVector3 location) { + return isHorizontallyInBounds(location.getX()) + && isHorizontallyInBounds(location.getZ()) + && WORLD_Y_MIN <= location.getY() && location.getY() <= WORLD_Y_MAX; + } + + public static void checkLongPackable(BlockVector3 location) { + checkArgument(isLongPackable(location), + "Location exceeds long packing limits: %s", location); + } + + private static final long BITS_26 = mask(26); + private static final long BITS_12 = mask(12); + + public static BlockVector3 fromLongPackedForm(long packed) { + return at(unpackX(packed), unpackY(packed), unpackZ(packed)); + } + + // thread-safe initialization idiom + private static final class YzxOrderComparator { + private static final Comparator YZX_ORDER = + Comparator.comparingInt(BlockVector3::getY) + .thenComparingInt(BlockVector3::getZ) + .thenComparingInt(BlockVector3::getX); + } + + /** + * Returns a comparator that sorts vectors first by Y, then Z, then X. + * + *

+ * Useful for sorting by chunk block storage order. + *

+ */ + public static Comparator sortByCoordsYzx() { + return YzxOrderComparator.YZX_ORDER; + } + + private final int x; + private final int y; + private final int z; + + /** + * Construct an instance. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + */ + private BlockVector3(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public long toLongPackedForm() { + checkLongPackable(this); + return (x & BITS_26) | ((z & BITS_26) << 26) | (((y & BITS_12) << (26 + 26))); + } + + /** + * Get the X coordinate. + * + * @return the x coordinate + */ + public int getX() { + return x; + } + + /** + * Get the X coordinate. + * + * @return the x coordinate + */ + public int getBlockX() { + return x; + } + + /** + * Set the X coordinate. + * + * @param x the new X + * @return a new vector + */ + public BlockVector3 withX(int x) { + return BlockVector3.at(x, y, z); + } + + /** + * Get the Y coordinate. + * + * @return the y coordinate + */ + public int getY() { + return y; + } + + /** + * Get the Y coordinate. + * + * @return the y coordinate + */ + public int getBlockY() { + return y; + } + + /** + * Set the Y coordinate. + * + * @param y the new Y + * @return a new vector + */ + public BlockVector3 withY(int y) { + return BlockVector3.at(x, y, z); + } + + /** + * Get the Z coordinate. + * + * @return the z coordinate + */ + public int getZ() { + return z; + } + + /** + * Get the Z coordinate. + * + * @return the z coordinate + */ + public int getBlockZ() { + return z; + } + + /** + * Set the Z coordinate. + * + * @param z the new Z + * @return a new vector + */ + public BlockVector3 withZ(int z) { + return BlockVector3.at(x, y, z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param other the other vector + * @return a new vector + */ + public BlockVector3 add(BlockVector3 other) { + return add(other.x, other.y, other.z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param x the value to add + * @param y the value to add + * @param z the value to add + * @return a new vector + */ + public BlockVector3 add(int x, int y, int z) { + return BlockVector3.at(this.x + x, this.y + y, this.z + z); + } + + /** + * Add a list of vectors to this vector and return the + * result as a new vector. + * + * @param others an array of vectors + * @return a new vector + */ + public BlockVector3 add(BlockVector3... others) { + int newX = x; + int newY = y; + int newZ = z; + + for (BlockVector3 other : others) { + newX += other.x; + newY += other.y; + newZ += other.z; + } + + return BlockVector3.at(newX, newY, newZ); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param other the other vector + * @return a new vector + */ + public BlockVector3 subtract(BlockVector3 other) { + return subtract(other.x, other.y, other.z); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param x the value to subtract + * @param y the value to subtract + * @param z the value to subtract + * @return a new vector + */ + public BlockVector3 subtract(int x, int y, int z) { + return BlockVector3.at(this.x - x, this.y - y, this.z - z); + } + + /** + * Subtract a list of vectors from this vector and return the result + * as a new vector. + * + * @param others an array of vectors + * @return a new vector + */ + public BlockVector3 subtract(BlockVector3... others) { + int newX = x; + int newY = y; + int newZ = z; + + for (BlockVector3 other : others) { + newX -= other.x; + newY -= other.y; + newZ -= other.z; + } + + return BlockVector3.at(newX, newY, newZ); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param other the other vector + * @return a new vector + */ + public BlockVector3 multiply(BlockVector3 other) { + return multiply(other.x, other.y, other.z); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param x the value to multiply + * @param y the value to multiply + * @param z the value to multiply + * @return a new vector + */ + public BlockVector3 multiply(int x, int y, int z) { + return BlockVector3.at(this.x * x, this.y * y, this.z * z); + } + + /** + * Multiply this vector by zero or more vectors on each component. + * + * @param others an array of vectors + * @return a new vector + */ + public BlockVector3 multiply(BlockVector3... others) { + int newX = x; + int newY = y; + int newZ = z; + + for (BlockVector3 other : others) { + newX *= other.x; + newY *= other.y; + newZ *= other.z; + } + + return BlockVector3.at(newX, newY, newZ); + } + + /** + * Perform scalar multiplication and return a new vector. + * + * @param n the value to multiply + * @return a new vector + */ + public BlockVector3 multiply(int n) { + return multiply(n, n, n); + } + + /** + * Divide this vector by another vector on each component. + * + * @param other the other vector + * @return a new vector + */ + public BlockVector3 divide(BlockVector3 other) { + return divide(other.x, other.y, other.z); + } + + /** + * Divide this vector by another vector on each component. + * + * @param x the value to divide by + * @param y the value to divide by + * @param z the value to divide by + * @return a new vector + */ + public BlockVector3 divide(int x, int y, int z) { + return BlockVector3.at(this.x / x, this.y / y, this.z / z); + } + + /** + * Perform scalar division and return a new vector. + * + * @param n the value to divide by + * @return a new vector + */ + public BlockVector3 divide(int n) { + return divide(n, n, n); + } + + /** + * Shift all components right. + * + * @param x the value to shift x by + * @param y the value to shift y by + * @param z the value to shift z by + * @return a new vector + */ + public BlockVector3 shr(int x, int y, int z) { + return at(this.x >> x, this.y >> y, this.z >> z); + } + + /** + * Shift all components right by {@code n}. + * + * @param n the value to shift by + * @return a new vector + */ + public BlockVector3 shr(int n) { + return shr(n, n, n); + } + + /** + * Shift all components left. + * + * @param x the value to shift x by + * @param y the value to shift y by + * @param z the value to shift z by + * @return a new vector + */ + public BlockVector3 shl(int x, int y, int z) { + return at(this.x << x, this.y << y, this.z << z); + } + + /** + * Shift all components left by {@code n}. + * + * @param n the value to shift by + * @return a new vector + */ + public BlockVector3 shl(int n) { + return shl(n, n, n); + } + + /** + * Get the length of the vector. + * + * @return length + */ + public double length() { + return Math.sqrt(lengthSq()); + } + + /** + * Get the length, squared, of the vector. + * + * @return length, squared + */ + public int lengthSq() { + return x * x + y * y + z * z; + } + + /** + * Get the distance between this vector and another vector. + * + * @param other the other vector + * @return distance + */ + public double distance(BlockVector3 other) { + return Math.sqrt(distanceSq(other)); + } + + /** + * Get the distance between this vector and another vector, squared. + * + * @param other the other vector + * @return distance + */ + public int distanceSq(BlockVector3 other) { + int dx = other.x - x; + int dy = other.y - y; + int dz = other.z - z; + return dx * dx + dy * dy + dz * dz; + } + + /** + * Get the normalized vector, which is the vector divided by its + * length, as a new vector. + * + * @return a new vector + */ + public BlockVector3 normalize() { + double len = length(); + double x = this.x / len; + double y = this.y / len; + double z = this.z / len; + return BlockVector3.at(x, y, z); + } + + /** + * Gets the dot product of this and another vector. + * + * @param other the other vector + * @return the dot product of this and the other vector + */ + public double dot(BlockVector3 other) { + return x * other.x + y * other.y + z * other.z; + } + + /** + * Gets the cross product of this and another vector. + * + * @param other the other vector + * @return the cross product of this and the other vector + */ + public BlockVector3 cross(BlockVector3 other) { + return new BlockVector3( + y * other.z - z * other.y, + z * other.x - x * other.z, + x * other.y - y * other.x + ); + } + + /** + * Checks to see if a vector is contained with another. + * + * @param min the minimum point (X, Y, and Z are the lowest) + * @param max the maximum point (X, Y, and Z are the lowest) + * @return true if the vector is contained + */ + public boolean containedWithin(BlockVector3 min, BlockVector3 max) { + return x >= min.x && x <= max.x && y >= min.y && y <= max.y && z >= min.z && z <= max.z; + } + + /** + * Clamp the Y component. + * + * @param min the minimum value + * @param max the maximum value + * @return a new vector + */ + public BlockVector3 clampY(int min, int max) { + checkArgument(min <= max, "minimum cannot be greater than maximum"); + if (y < min) { + return BlockVector3.at(x, min, z); + } + if (y > max) { + return BlockVector3.at(x, max, z); + } + return this; + } + + /** + * Floors the values of all components. + * + * @return a new vector + */ + public BlockVector3 floor() { + // already floored, kept for feature parity with Vector3 + return this; + } + + /** + * Rounds all components up. + * + * @return a new vector + */ + public BlockVector3 ceil() { + // already raised, kept for feature parity with Vector3 + return this; + } + + /** + * Rounds all components to the closest integer. + * + *

Components < 0.5 are rounded down, otherwise up.

+ * + * @return a new vector + */ + public BlockVector3 round() { + // already rounded, kept for feature parity with Vector3 + return this; + } + + /** + * Returns a vector with the absolute values of the components of + * this vector. + * + * @return a new vector + */ + public BlockVector3 abs() { + return BlockVector3.at(Math.abs(x), Math.abs(y), Math.abs(z)); + } + + /** + * Perform a 2D transformation on this vector and return a new one. + * + * @param angle in degrees + * @param aboutX about which x coordinate to rotate + * @param aboutZ about which z coordinate to rotate + * @param translateX what to add after rotation + * @param translateZ what to add after rotation + * @return a new vector + * @see AffineTransform another method to transform vectors + */ + public BlockVector3 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { + angle = Math.toRadians(angle); + double x = this.x - aboutX; + double z = this.z - aboutZ; + double cos = Math.cos(angle); + double sin = Math.sin(angle); + double x2 = x * cos - z * sin; + double z2 = x * sin + z * cos; + + return BlockVector3.at( + x2 + aboutX + translateX, + y, + z2 + aboutZ + translateZ + ); + } + + /** + * Get this vector's pitch as used within the game. + * + * @return pitch in radians + */ + public double toPitch() { + double x = getX(); + double z = getZ(); + + if (x == 0 && z == 0) { + return getY() > 0 ? -90 : 90; + } else { + double x2 = x * x; + double z2 = z * z; + double xz = Math.sqrt(x2 + z2); + return Math.toDegrees(Math.atan(-getY() / xz)); + } + } + + /** + * Get this vector's yaw as used within the game. + * + * @return yaw in radians + */ + public double toYaw() { + double x = getX(); + double z = getZ(); + + double t = Math.atan2(-x, z); + double tau = 2 * Math.PI; + + return Math.toDegrees(((t + tau) % tau)); + } + + /** + * Gets the minimum components of two vectors. + * + * @param v2 the second vector + * @return minimum + */ + public BlockVector3 getMinimum(BlockVector3 v2) { + return new BlockVector3( + Math.min(x, v2.x), + Math.min(y, v2.y), + Math.min(z, v2.z) + ); + } + + /** + * Gets the maximum components of two vectors. + * + * @param v2 the second vector + * @return maximum + */ + public BlockVector3 getMaximum(BlockVector3 v2) { + return new BlockVector3( + Math.max(x, v2.x), + Math.max(y, v2.y), + Math.max(z, v2.z) + ); + } + + /** + * Creates a 2D vector by dropping the Y component from this vector. + * + * @return a new {@link BlockVector2} + */ + public BlockVector2 toBlockVector2() { + return BlockVector2.at(x, z); + } + + public Vector3 toVector3() { + return Vector3.at(x, y, z); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof BlockVector3)) { + return false; + } + + BlockVector3 other = (BlockVector3) obj; + return other.x == this.x && other.y == this.y && other.z == this.z; + } + + @Override + public int hashCode() { + return (x ^ (z << 12)) ^ (y << 24); + } + + @Override + public String toString() { + return "(" + x + ", " + y + ", " + z + ")"; + } + + /** + * Returns a string representation that is supported by the parser. + * @return string + */ + public String toParserString() { + return x + "," + y + "," + z; + } +} diff --git a/src/main/java/com/sk89q/worldedit/math/MathUtils.java b/src/main/java/com/sk89q/worldedit/math/MathUtils.java new file mode 100644 index 0000000..897baad --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/MathUtils.java @@ -0,0 +1,126 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math; + +/** + * Various math utility methods. + */ +public final class MathUtils { + + /** + * Safe minimum, such that 1 / SAFE_MIN does not overflow. + * + *

In IEEE 754 arithmetic, this is also the smallest normalized number + * 2-1022. The value of this constant is from Apache Commons + * Math 2.2.

+ */ + public static final double SAFE_MIN = 0x1.0p-1022; + + private MathUtils() { + } + + /** + * Modulus, divisor-style. + * + * @param a a + * @param n n + * @return the modulus + */ + public static int divisorMod(int a, int n) { + return (int) (a - n * Math.floor(Math.floor(a) / n)); + } + + /** + * Returns the cosine of an angle given in degrees. This is better than + * just {@code Math.cos(Math.toRadians(degrees))} because it provides a + * more accurate result for angles divisible by 90 degrees. + * + * @param degrees the angle + * @return the cosine of the given angle + */ + public static double dCos(double degrees) { + int dInt = (int) degrees; + if (degrees == dInt && dInt % 90 == 0) { + dInt %= 360; + if (dInt < 0) { + dInt += 360; + } + switch (dInt) { + case 0: + return 1.0; + case 90: + return 0.0; + case 180: + return -1.0; + case 270: + return 0.0; + default: + break; + } + } + return Math.cos(Math.toRadians(degrees)); + } + + /** + * Returns the sine of an angle given in degrees. This is better than just + * {@code Math.sin(Math.toRadians(degrees))} because it provides a more + * accurate result for angles divisible by 90 degrees. + * + * @param degrees the angle + * @return the sine of the given angle + */ + public static double dSin(double degrees) { + int dInt = (int) degrees; + if (degrees == dInt && dInt % 90 == 0) { + dInt %= 360; + if (dInt < 0) { + dInt += 360; + } + switch (dInt) { + case 0: + return 0.0; + case 90: + return 1.0; + case 180: + return 0.0; + case 270: + return -1.0; + default: + break; + } + } + return Math.sin(Math.toRadians(degrees)); + } + + /** + * Returns the rounded double of the given value, rounding to the + * nearest integer value away from zero on ties. + * + *

+ * This behavior is the same as {@link java.math.RoundingMode#HALF_UP}. + *

+ * + * @param value the value + * @return the rounded value + */ + public static double roundHalfUp(double value) { + return Math.signum(value) * Math.round(Math.abs(value)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/math/RegionOptimizedChunkComparator.java b/src/main/java/com/sk89q/worldedit/math/RegionOptimizedChunkComparator.java new file mode 100644 index 0000000..09d0aaf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/RegionOptimizedChunkComparator.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math; + +import java.util.Comparator; + +import static com.sk89q.worldedit.math.BlockVector2.COMPARING_GRID_ARRANGEMENT; + +/** + * Sort block positions by region, then chunk. + */ +public class RegionOptimizedChunkComparator { + + private static final Comparator CHUNK_COMPARATOR = + Comparator.comparing((BlockVector2 chunkPos) -> chunkPos.shr(5), COMPARING_GRID_ARRANGEMENT) + .thenComparing(COMPARING_GRID_ARRANGEMENT); + + public static final Comparator INSTANCE + = Comparator.comparing(blockPos -> blockPos.toBlockVector2().shr(4), CHUNK_COMPARATOR); + + private RegionOptimizedChunkComparator() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/RegionOptimizedComparator.java b/src/main/java/com/sk89q/worldedit/math/RegionOptimizedComparator.java new file mode 100644 index 0000000..8bfb1af --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/RegionOptimizedComparator.java @@ -0,0 +1,36 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math; + +import java.util.Comparator; + +/** + * Sort block positions by region, chunk, and finally Y-Z-X. + */ +public class RegionOptimizedComparator { + + public static final Comparator INSTANCE + = RegionOptimizedChunkComparator.INSTANCE + .thenComparing(BlockVector3.sortByCoordsYzx()); + + private RegionOptimizedComparator() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/Vector2.java b/src/main/java/com/sk89q/worldedit/math/Vector2.java new file mode 100644 index 0000000..f511f18 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/Vector2.java @@ -0,0 +1,491 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math; + +import com.sk89q.worldedit.math.transform.AffineTransform; + +/** + * An immutable 2-dimensional vector. + */ +public final class Vector2 { + + public static final Vector2 ZERO = new Vector2(0, 0); + public static final Vector2 UNIT_X = new Vector2(1, 0); + public static final Vector2 UNIT_Z = new Vector2(0, 1); + public static final Vector2 ONE = new Vector2(1, 1); + + public static Vector2 at(double x, double z) { + int xTrunc = (int) x; + switch (xTrunc) { + case 0: + if (x == 0 && z == 0) { + return ZERO; + } + break; + case 1: + if (x == 1 && z == 1) { + return ONE; + } + break; + default: + break; + } + return new Vector2(x, z); + } + + private final double x; + private final double z; + + /** + * Construct an instance. + * + * @param x the X coordinate + * @param z the Z coordinate + */ + private Vector2(double x, double z) { + this.x = x; + this.z = z; + } + + /** + * Get the X coordinate. + * + * @return the x coordinate + */ + public double getX() { + return x; + } + + /** + * Set the X coordinate. + * + * @param x the new X + * @return a new vector + */ + public Vector2 withX(double x) { + return Vector2.at(x, z); + } + + /** + * Get the Z coordinate. + * + * @return the z coordinate + */ + public double getZ() { + return z; + } + + /** + * Set the Z coordinate. + * + * @param z the new Z + * @return a new vector + */ + public Vector2 withZ(double z) { + return Vector2.at(x, z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param other the other vector + * @return a new vector + */ + public Vector2 add(Vector2 other) { + return add(other.x, other.z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param x the value to add + * @param z the value to add + * @return a new vector + */ + public Vector2 add(double x, double z) { + return Vector2.at(this.x + x, this.z + z); + } + + /** + * Add a list of vectors to this vector and return the + * result as a new vector. + * + * @param others an array of vectors + * @return a new vector + */ + public Vector2 add(Vector2... others) { + double newX = x; + double newZ = z; + + for (Vector2 other : others) { + newX += other.x; + newZ += other.z; + } + + return Vector2.at(newX, newZ); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param other the other vector + * @return a new vector + */ + public Vector2 subtract(Vector2 other) { + return subtract(other.x, other.z); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param x the value to subtract + * @param z the value to subtract + * @return a new vector + */ + public Vector2 subtract(double x, double z) { + return Vector2.at(this.x - x, this.z - z); + } + + /** + * Subtract a list of vectors from this vector and return the result + * as a new vector. + * + * @param others an array of vectors + * @return a new vector + */ + public Vector2 subtract(Vector2... others) { + double newX = x; + double newZ = z; + + for (Vector2 other : others) { + newX -= other.x; + newZ -= other.z; + } + + return Vector2.at(newX, newZ); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param other the other vector + * @return a new vector + */ + public Vector2 multiply(Vector2 other) { + return multiply(other.x, other.z); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param x the value to multiply + * @param z the value to multiply + * @return a new vector + */ + public Vector2 multiply(double x, double z) { + return Vector2.at(this.x * x, this.z * z); + } + + /** + * Multiply this vector by zero or more vectors on each component. + * + * @param others an array of vectors + * @return a new vector + */ + public Vector2 multiply(Vector2... others) { + double newX = x; + double newZ = z; + + for (Vector2 other : others) { + newX *= other.x; + newZ *= other.z; + } + + return Vector2.at(newX, newZ); + } + + /** + * Perform scalar multiplication and return a new vector. + * + * @param n the value to multiply + * @return a new vector + */ + public Vector2 multiply(double n) { + return multiply(n, n); + } + + /** + * Divide this vector by another vector on each component. + * + * @param other the other vector + * @return a new vector + */ + public Vector2 divide(Vector2 other) { + return divide(other.x, other.z); + } + + /** + * Divide this vector by another vector on each component. + * + * @param x the value to divide by + * @param z the value to divide by + * @return a new vector + */ + public Vector2 divide(double x, double z) { + return Vector2.at(this.x / x, this.z / z); + } + + /** + * Perform scalar division and return a new vector. + * + * @param n the value to divide by + * @return a new vector + */ + public Vector2 divide(double n) { + return divide(n, n); + } + + /** + * Get the length of the vector. + * + * @return length + */ + public double length() { + return Math.sqrt(lengthSq()); + } + + /** + * Get the length, squared, of the vector. + * + * @return length, squared + */ + public double lengthSq() { + return x * x + z * z; + } + + /** + * Get the distance between this vector and another vector. + * + * @param other the other vector + * @return distance + */ + public double distance(Vector2 other) { + return Math.sqrt(distanceSq(other)); + } + + /** + * Get the distance between this vector and another vector, squared. + * + * @param other the other vector + * @return distance + */ + public double distanceSq(Vector2 other) { + double dx = other.x - x; + double dz = other.z - z; + return dx * dx + dz * dz; + } + + /** + * Get the normalized vector, which is the vector divided by its + * length, as a new vector. + * + * @return a new vector + */ + public Vector2 normalize() { + return divide(length()); + } + + /** + * Gets the dot product of this and another vector. + * + * @param other the other vector + * @return the dot product of this and the other vector + */ + public double dot(Vector2 other) { + return x * other.x + z * other.z; + } + + /** + * Checks to see if a vector is contained with another. + * + * @param min the minimum point (X, Y, and Z are the lowest) + * @param max the maximum point (X, Y, and Z are the lowest) + * @return true if the vector is contained + */ + public boolean containedWithin(Vector2 min, Vector2 max) { + return x >= min.x && x <= max.x + && z >= min.z && z <= max.z; + } + + /** + * Floors the values of all components. + * + * @return a new vector + */ + public Vector2 floor() { + return Vector2.at(Math.floor(x), Math.floor(z)); + } + + /** + * Rounds all components up. + * + * @return a new vector + */ + public Vector2 ceil() { + return Vector2.at(Math.ceil(x), Math.ceil(z)); + } + + /** + * Rounds all components to the closest integer. + * + *

Components < 0.5 are rounded down, otherwise up.

+ * + * @return a new vector + */ + public Vector2 round() { + return Vector2.at(Math.floor(x + 0.5), Math.floor(z + 0.5)); + } + + /** + * Returns a vector with the absolute values of the components of + * this vector. + * + * @return a new vector + */ + public Vector2 abs() { + return Vector2.at(Math.abs(x), Math.abs(z)); + } + + /** + * Perform a 2D transformation on this vector and return a new one. + * + * @param angle in degrees + * @param aboutX about which x coordinate to rotate + * @param aboutZ about which z coordinate to rotate + * @param translateX what to add after rotation + * @param translateZ what to add after rotation + * @return a new vector + * @see AffineTransform another method to transform vectors + */ + public Vector2 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { + angle = Math.toRadians(angle); + double x = this.x - aboutX; + double z = this.z - aboutZ; + double cos = Math.cos(angle); + double sin = Math.sin(angle); + double x2 = x * cos - z * sin; + double z2 = x * sin + z * cos; + return new Vector2( + x2 + aboutX + translateX, + z2 + aboutZ + translateZ); + } + + /** + * Gets the minimum components of two vectors. + * + * @param v2 the second vector + * @return minimum + */ + public Vector2 getMinimum(Vector2 v2) { + return new Vector2( + Math.min(x, v2.x), + Math.min(z, v2.z) + ); + } + + /** + * Gets the maximum components of two vectors. + * + * @param v2 the second vector + * @return maximum + */ + public Vector2 getMaximum(Vector2 v2) { + return new Vector2( + Math.max(x, v2.x), + Math.max(z, v2.z) + ); + } + + public static BlockVector2 toBlockPoint(double x, double z) { + return BlockVector2.at(x, z); + } + + /** + * Create a new {@link BlockVector2} from this vector. + * + * @return a new {@link BlockVector2} + */ + public BlockVector2 toBlockPoint() { + return toBlockPoint(x, z); + } + + /** + * Creates a 3D vector by adding a zero Y component to this vector. + * + * @return a new vector + */ + public Vector3 toVector3() { + return toVector3(0); + } + + /** + * Creates a 3D vector by adding the specified Y component to this vector. + * + * @param y the Y component + * @return a new vector + */ + public Vector3 toVector3(double y) { + return Vector3.at(x, y, z); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Vector2)) { + return false; + } + + Vector2 other = (Vector2) obj; + return other.x == this.x && other.z == this.z; + + } + + @Override + public int hashCode() { + int hash = 17; + hash = 31 * hash + Double.hashCode(x); + hash = 31 * hash + Double.hashCode(z); + return hash; + } + + @Override + public String toString() { + return "(" + x + ", " + z + ")"; + } + + /** + * Returns a string representation that is supported by the parser. + * @return string + */ + public String toParserString() { + return x + "," + z; + } +} diff --git a/src/main/java/com/sk89q/worldedit/math/Vector3.java b/src/main/java/com/sk89q/worldedit/math/Vector3.java new file mode 100644 index 0000000..e100aed --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/Vector3.java @@ -0,0 +1,622 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math; + +import com.google.common.collect.ComparisonChain; +import com.sk89q.worldedit.math.transform.AffineTransform; + +import java.util.Comparator; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * An immutable 3-dimensional vector. + */ +public final class Vector3 { + + public static final Vector3 ZERO = new Vector3(0, 0, 0); + public static final Vector3 UNIT_X = new Vector3(1, 0, 0); + public static final Vector3 UNIT_Y = new Vector3(0, 1, 0); + public static final Vector3 UNIT_Z = new Vector3(0, 0, 1); + public static final Vector3 ONE = new Vector3(1, 1, 1); + + public static Vector3 at(double x, double y, double z) { + // switch for efficiency on typical cases + // in MC y is rarely 0/1 on selections + int yTrunc = (int) y; + switch (yTrunc) { + case 0: + if (x == 0 && y == 0 && z == 0) { + return ZERO; + } + break; + case 1: + if (x == 1 && y == 1 && z == 1) { + return ONE; + } + break; + default: + break; + } + return new Vector3(x, y, z); + } + + // thread-safe initialization idiom + private static final class YzxOrderComparator { + private static final Comparator YZX_ORDER = (a, b) -> { + return ComparisonChain.start() + .compare(a.y, b.y) + .compare(a.z, b.z) + .compare(a.x, b.x) + .result(); + }; + } + + /** + * Returns a comparator that sorts vectors first by Y, then Z, then X. + * + *

+ * Useful for sorting by chunk block storage order. + *

+ */ + public static Comparator sortByCoordsYzx() { + return YzxOrderComparator.YZX_ORDER; + } + + private final double x; + private final double y; + private final double z; + + /** + * Construct an instance. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + */ + private Vector3(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Get the X coordinate. + * + * @return the x coordinate + */ + public double getX() { + return x; + } + + /** + * Set the X coordinate. + * + * @param x the new X + * @return a new vector + */ + public Vector3 withX(double x) { + return Vector3.at(x, y, z); + } + + /** + * Get the Y coordinate. + * + * @return the y coordinate + */ + public double getY() { + return y; + } + + /** + * Set the Y coordinate. + * + * @param y the new Y + * @return a new vector + */ + public Vector3 withY(double y) { + return Vector3.at(x, y, z); + } + + /** + * Get the Z coordinate. + * + * @return the z coordinate + */ + public double getZ() { + return z; + } + + /** + * Set the Z coordinate. + * + * @param z the new Z + * @return a new vector + */ + public Vector3 withZ(double z) { + return Vector3.at(x, y, z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param other the other vector + * @return a new vector + */ + public Vector3 add(Vector3 other) { + return add(other.x, other.y, other.z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param x the value to add + * @param y the value to add + * @param z the value to add + * @return a new vector + */ + public Vector3 add(double x, double y, double z) { + return Vector3.at(this.x + x, this.y + y, this.z + z); + } + + /** + * Add a list of vectors to this vector and return the + * result as a new vector. + * + * @param others an array of vectors + * @return a new vector + */ + public Vector3 add(Vector3... others) { + double newX = x; + double newY = y; + double newZ = z; + + for (Vector3 other : others) { + newX += other.x; + newY += other.y; + newZ += other.z; + } + + return Vector3.at(newX, newY, newZ); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param other the other vector + * @return a new vector + */ + public Vector3 subtract(Vector3 other) { + return subtract(other.x, other.y, other.z); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param x the value to subtract + * @param y the value to subtract + * @param z the value to subtract + * @return a new vector + */ + public Vector3 subtract(double x, double y, double z) { + return Vector3.at(this.x - x, this.y - y, this.z - z); + } + + /** + * Subtract a list of vectors from this vector and return the result + * as a new vector. + * + * @param others an array of vectors + * @return a new vector + */ + public Vector3 subtract(Vector3... others) { + double newX = x; + double newY = y; + double newZ = z; + + for (Vector3 other : others) { + newX -= other.x; + newY -= other.y; + newZ -= other.z; + } + + return Vector3.at(newX, newY, newZ); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param other the other vector + * @return a new vector + */ + public Vector3 multiply(Vector3 other) { + return multiply(other.x, other.y, other.z); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param x the value to multiply + * @param y the value to multiply + * @param z the value to multiply + * @return a new vector + */ + public Vector3 multiply(double x, double y, double z) { + return Vector3.at(this.x * x, this.y * y, this.z * z); + } + + /** + * Multiply this vector by zero or more vectors on each component. + * + * @param others an array of vectors + * @return a new vector + */ + public Vector3 multiply(Vector3... others) { + double newX = x; + double newY = y; + double newZ = z; + + for (Vector3 other : others) { + newX *= other.x; + newY *= other.y; + newZ *= other.z; + } + + return Vector3.at(newX, newY, newZ); + } + + /** + * Perform scalar multiplication and return a new vector. + * + * @param n the value to multiply + * @return a new vector + */ + public Vector3 multiply(double n) { + return multiply(n, n, n); + } + + /** + * Divide this vector by another vector on each component. + * + * @param other the other vector + * @return a new vector + */ + public Vector3 divide(Vector3 other) { + return divide(other.x, other.y, other.z); + } + + /** + * Divide this vector by another vector on each component. + * + * @param x the value to divide by + * @param y the value to divide by + * @param z the value to divide by + * @return a new vector + */ + public Vector3 divide(double x, double y, double z) { + return Vector3.at(this.x / x, this.y / y, this.z / z); + } + + /** + * Perform scalar division and return a new vector. + * + * @param n the value to divide by + * @return a new vector + */ + public Vector3 divide(double n) { + return divide(n, n, n); + } + + /** + * Get the length of the vector. + * + * @return length + */ + public double length() { + return Math.sqrt(lengthSq()); + } + + /** + * Get the length, squared, of the vector. + * + * @return length, squared + */ + public double lengthSq() { + return x * x + y * y + z * z; + } + + /** + * Get the distance between this vector and another vector. + * + * @param other the other vector + * @return distance + */ + public double distance(Vector3 other) { + return Math.sqrt(distanceSq(other)); + } + + /** + * Get the distance between this vector and another vector, squared. + * + * @param other the other vector + * @return distance + */ + public double distanceSq(Vector3 other) { + double dx = other.x - x; + double dy = other.y - y; + double dz = other.z - z; + return dx * dx + dy * dy + dz * dz; + } + + /** + * Get the normalized vector, which is the vector divided by its + * length, as a new vector. + * + * @return a new vector + */ + public Vector3 normalize() { + return divide(length()); + } + + /** + * Gets the dot product of this and another vector. + * + * @param other the other vector + * @return the dot product of this and the other vector + */ + public double dot(Vector3 other) { + return x * other.x + y * other.y + z * other.z; + } + + /** + * Gets the cross product of this and another vector. + * + * @param other the other vector + * @return the cross product of this and the other vector + */ + public Vector3 cross(Vector3 other) { + return new Vector3( + y * other.z - z * other.y, + z * other.x - x * other.z, + x * other.y - y * other.x + ); + } + + /** + * Checks to see if a vector is contained with another. + * + * @param min the minimum point (X, Y, and Z are the lowest) + * @param max the maximum point (X, Y, and Z are the lowest) + * @return true if the vector is contained + */ + public boolean containedWithin(Vector3 min, Vector3 max) { + return x >= min.x && x <= max.x && y >= min.y && y <= max.y && z >= min.z && z <= max.z; + } + + /** + * Clamp the Y component. + * + * @param min the minimum value + * @param max the maximum value + * @return a new vector + */ + public Vector3 clampY(int min, int max) { + checkArgument(min <= max, "minimum cannot be greater than maximum"); + if (y < min) { + return Vector3.at(x, min, z); + } + if (y > max) { + return Vector3.at(x, max, z); + } + return this; + } + + /** + * Floors the values of all components. + * + * @return a new vector + */ + public Vector3 floor() { + return Vector3.at(Math.floor(x), Math.floor(y), Math.floor(z)); + } + + /** + * Rounds all components up. + * + * @return a new vector + */ + public Vector3 ceil() { + return Vector3.at(Math.ceil(x), Math.ceil(y), Math.ceil(z)); + } + + /** + * Rounds all components to the closest integer. + * + *

Components < 0.5 are rounded down, otherwise up.

+ * + * @return a new vector + */ + public Vector3 round() { + return Vector3.at(Math.floor(x + 0.5), Math.floor(y + 0.5), Math.floor(z + 0.5)); + } + + /** + * Returns a vector with the absolute values of the components of + * this vector. + * + * @return a new vector + */ + public Vector3 abs() { + return Vector3.at(Math.abs(x), Math.abs(y), Math.abs(z)); + } + + /** + * Perform a 2D transformation on this vector and return a new one. + * + * @param angle in degrees + * @param aboutX about which x coordinate to rotate + * @param aboutZ about which z coordinate to rotate + * @param translateX what to add after rotation + * @param translateZ what to add after rotation + * @return a new vector + * @see AffineTransform another method to transform vectors + */ + public Vector3 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { + angle = Math.toRadians(angle); + double x = this.x - aboutX; + double z = this.z - aboutZ; + double cos = Math.cos(angle); + double sin = Math.sin(angle); + double x2 = x * cos - z * sin; + double z2 = x * sin + z * cos; + + return new Vector3( + x2 + aboutX + translateX, + y, + z2 + aboutZ + translateZ + ); + } + + /** + * Get this vector's pitch as used within the game. + * + * @return pitch in radians + */ + public double toPitch() { + double x = getX(); + double z = getZ(); + + if (x == 0 && z == 0) { + return getY() > 0 ? -90 : 90; + } else { + double x2 = x * x; + double z2 = z * z; + double xz = Math.sqrt(x2 + z2); + return Math.toDegrees(Math.atan(-getY() / xz)); + } + } + + /** + * Get this vector's yaw as used within the game. + * + * @return yaw in radians + */ + public double toYaw() { + double x = getX(); + double z = getZ(); + + double t = Math.atan2(-x, z); + double tau = 2 * Math.PI; + + return Math.toDegrees(((t + tau) % tau)); + } + + /** + * Gets the minimum components of two vectors. + * + * @param v2 the second vector + * @return minimum + */ + public Vector3 getMinimum(Vector3 v2) { + return new Vector3( + Math.min(x, v2.x), + Math.min(y, v2.y), + Math.min(z, v2.z) + ); + } + + /** + * Gets the maximum components of two vectors. + * + * @param v2 the second vector + * @return maximum + */ + public Vector3 getMaximum(Vector3 v2) { + return new Vector3( + Math.max(x, v2.x), + Math.max(y, v2.y), + Math.max(z, v2.z) + ); + } + + /** + * Create a new {@code BlockVector} using the given components. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + * @return a new {@code BlockVector} + */ + public static BlockVector3 toBlockPoint(double x, double y, double z) { + return BlockVector3.at(x, y, z); + } + + /** + * Create a new {@code BlockVector} from this vector. + * + * @return a new {@code BlockVector} + */ + public BlockVector3 toBlockPoint() { + return toBlockPoint(x, y, z); + } + + /** + * Creates a 2D vector by dropping the Y component from this vector. + * + * @return a new {@link Vector2} + */ + public Vector2 toVector2() { + return Vector2.at(x, z); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Vector3)) { + return false; + } + + Vector3 other = (Vector3) obj; + return other.x == this.x && other.y == this.y && other.z == this.z; + } + + @Override + public int hashCode() { + int hash = 17; + hash = 31 * hash + Double.hashCode(x); + hash = 31 * hash + Double.hashCode(y); + hash = 31 * hash + Double.hashCode(z); + return hash; + } + + @Override + public String toString() { + return "(" + x + ", " + y + ", " + z + ")"; + } + + /** + * Returns a string representation that is supported by the parser. + * @return string + */ + public String toParserString() { + return x + "," + y + "," + z; + } +} diff --git a/src/main/java/com/sk89q/worldedit/math/convolution/GaussianKernel.java b/src/main/java/com/sk89q/worldedit/math/convolution/GaussianKernel.java new file mode 100644 index 0000000..31dec0c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/convolution/GaussianKernel.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.convolution; + +/** + * A Gaussian Kernel generator (2D bellcurve). + */ +public class GaussianKernel extends Kernel { + + /** + * Constructor of the kernel. + * + * @param radius the resulting diameter will be radius * 2 + 1 + * @param sigma controls 'flatness' + */ + public GaussianKernel(int radius, double sigma) { + super(radius * 2 + 1, radius * 2 + 1, createKernel(radius, sigma)); + } + + private static float[] createKernel(int radius, double sigma) { + int diameter = radius * 2 + 1; + float[] data = new float[diameter * diameter]; + + double sigma22 = 2 * sigma * sigma; + double constant = Math.PI * sigma22; + for (int y = -radius; y <= radius; ++y) { + for (int x = -radius; x <= radius; ++x) { + data[(y + radius) * diameter + x + radius] = (float) (Math.exp(-(x * x + y * y) / sigma22) / constant); + } + } + + return data; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java b/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java new file mode 100644 index 0000000..c58e874 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java @@ -0,0 +1,179 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.convolution; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Allows applications of Kernels onto the region's height map. + * + *

Currently only used for smoothing (with a GaussianKernel)

. + */ +public class HeightMap { + + private final int[] data; + private final int width; + private final int height; + + private final Region region; + private final EditSession session; + + /** + * Constructs the HeightMap. + * + * @param session an edit session + * @param region the region + */ + public HeightMap(EditSession session, Region region, @Nullable Mask mask) { + checkNotNull(session); + checkNotNull(region); + + this.session = session; + this.region = region; + + this.width = region.getWidth(); + this.height = region.getLength(); + + int minX = region.getMinimumPoint().getBlockX(); + int minY = region.getMinimumPoint().getBlockY(); + int minZ = region.getMinimumPoint().getBlockZ(); + int maxY = region.getMaximumPoint().getBlockY(); + + // Store current heightmap data + data = new int[width * height]; + for (int z = 0; z < height; ++z) { + for (int x = 0; x < width; ++x) { + data[z * width + x] = session.getHighestTerrainBlock(x + minX, z + minZ, minY, maxY, mask); + } + } + } + + /** + * Apply the filter 'iterations' amount times. + * + * @param filter the filter + * @param iterations the number of iterations + * @return number of blocks affected + * @throws MaxChangedBlocksException if the maximum block change limit is exceeded + */ + public int applyFilter(HeightMapFilter filter, int iterations) throws MaxChangedBlocksException { + checkNotNull(filter); + + int[] newData = new int[data.length]; + System.arraycopy(data, 0, newData, 0, data.length); + + for (int i = 0; i < iterations; ++i) { + newData = filter.filter(newData, width, height); + } + + return apply(newData); + } + + /** + * Apply a raw heightmap to the region. + * + * @param data the data + * @return number of blocks affected + * @throws MaxChangedBlocksException if the maximum block change limit is exceeded + */ + public int apply(int[] data) throws MaxChangedBlocksException { + checkNotNull(data); + + BlockVector3 minY = region.getMinimumPoint(); + int originX = minY.getBlockX(); + int originY = minY.getBlockY(); + int originZ = minY.getBlockZ(); + + int maxY = region.getMaximumPoint().getBlockY(); + BlockState fillerAir = BlockTypes.AIR.getDefaultState(); + + int blocksChanged = 0; + + // Apply heightmap + for (int z = 0; z < height; ++z) { + for (int x = 0; x < width; ++x) { + int index = z * width + x; + int curHeight = this.data[index]; + + // Clamp newHeight within the selection area + int newHeight = Math.min(maxY, data[index]); + + // Offset x,z to be 'real' coordinates + int xr = x + originX; + int zr = z + originZ; + + // We are keeping the topmost blocks so take that in account for the scale + double scale = (double) (curHeight - originY) / (double) (newHeight - originY); + + // Depending on growing or shrinking we need to start at the bottom or top + if (newHeight > curHeight) { + // Set the top block of the column to be the same type (this might go wrong with rounding) + BlockState existing = session.getBlock(BlockVector3.at(xr, curHeight, zr)); + + // Skip water/lava + if (existing.getBlockType() != BlockTypes.WATER && existing.getBlockType() != BlockTypes.LAVA) { + session.setBlock(BlockVector3.at(xr, newHeight, zr), existing); + ++blocksChanged; + + // Grow -- start from 1 below top replacing airblocks + for (int y = newHeight - 1 - originY; y >= 0; --y) { + int copyFrom = (int) Math.floor(y * scale); + session.setBlock(BlockVector3.at(xr, originY + y, zr), session.getBlock(BlockVector3.at(xr, originY + copyFrom, zr))); + ++blocksChanged; + } + } + } else if (curHeight > newHeight) { + // Shrink -- start from bottom + for (int y = 0; y < newHeight - originY; ++y) { + int copyFrom = (int) Math.floor(y * scale); + session.setBlock(BlockVector3.at(xr, originY + y, zr), session.getBlock(BlockVector3.at(xr, originY + copyFrom, zr))); + ++blocksChanged; + } + + // Set the top block of the column to be the same type + // (this could otherwise go wrong with rounding) + session.setBlock(BlockVector3.at(xr, newHeight, zr), session.getBlock(BlockVector3.at(xr, curHeight, zr))); + ++blocksChanged; + + // Fill rest with air + for (int y = newHeight + 1; y <= curHeight; ++y) { + session.setBlock(BlockVector3.at(xr, y, zr), fillerAir); + ++blocksChanged; + } + } + } + } + + // Drop trees to the floor -- TODO + + return blocksChanged; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java b/src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java new file mode 100644 index 0000000..0333901 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java @@ -0,0 +1,129 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.convolution; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Allows applications of Kernels onto the region's height map. + * + *

Only used for smoothing (with a GaussianKernel).

+ */ +public class HeightMapFilter { + + private Kernel kernel; + + /** + * Construct the HeightMapFilter object. + * + * @param kernel the kernel + */ + public HeightMapFilter(Kernel kernel) { + checkNotNull(kernel); + this.kernel = kernel; + } + + /** + * Construct the HeightMapFilter object. + * + * @param kernelWidth the width + * @param kernelHeight the height + * @param kernelData the data + */ + public HeightMapFilter(int kernelWidth, int kernelHeight, float[] kernelData) { + checkNotNull(kernelData); + this.kernel = new Kernel(kernelWidth, kernelHeight, kernelData); + } + + /** + * Get the kernel. + */ + public Kernel getKernel() { + return kernel; + } + + /** + * Set the kernel. + * + * @param kernel the kernel + */ + public void setKernel(Kernel kernel) { + checkNotNull(kernel); + + this.kernel = kernel; + } + + /** + * Filter with a 2D kernel. + * + * @param inData the data + * @param width the width + * @param height the height + * + * @return the modified height map + */ + public int[] filter(int[] inData, int width, int height) { + checkNotNull(inData); + + int index = 0; + float[] matrix = kernel.getKernelData(null); + int[] outData = new int[inData.length]; + + int kh = kernel.getHeight(); + int kw = kernel.getWidth(); + int kox = kernel.getXOrigin(); + int koy = kernel.getYOrigin(); + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + float z = 0; + + for (int ky = 0; ky < kh; ++ky) { + int offsetY = y + ky - koy; + // Clamp coordinates inside data + if (offsetY < 0 || offsetY >= height) { + offsetY = y; + } + + offsetY *= width; + + int matrixOffset = ky * kw; + for (int kx = 0; kx < kw; ++kx) { + float f = matrix[matrixOffset + kx]; + if (f == 0) { + continue; + } + + int offsetX = x + kx - kox; + // Clamp coordinates inside data + if (offsetX < 0 || offsetX >= width) { + offsetX = x; + } + + z += f * inData[offsetY + offsetX]; + } + } + outData[index++] = (int) Math.floor(z + 0.5); + } + } + return outData; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/convolution/Kernel.java b/src/main/java/com/sk89q/worldedit/math/convolution/Kernel.java new file mode 100644 index 0000000..7e04e66 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/convolution/Kernel.java @@ -0,0 +1,75 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.convolution; + +/* + * This class was originally part of the JDK, java.awt.image.Kernel, + * and has been modified to not load the entire AWT toolkit, since + * that was apparently added in Java 8, even though this class + * is completely standalone. + */ +public class Kernel { + + private final int width; + private final int height; + private final int xOrigin; + private final int yOrigin; + private final float[] data; + + public Kernel(int width, int height, float[] data) { + this.width = width; + this.height = height; + this.xOrigin = (width - 1) >> 1; + this.yOrigin = (height - 1) >> 1; + int len = width * height; + if (data.length < len) { + throw new IllegalArgumentException("Data array too small (is " + data.length + " and should be " + len); + } + this.data = new float[len]; + System.arraycopy(data, 0, this.data, 0, len); + } + + public final int getXOrigin() { + return xOrigin; + } + + public final int getYOrigin() { + return yOrigin; + } + + public final int getWidth() { + return width; + } + + public final int getHeight() { + return height; + } + + public final float[] getKernelData(float[] data) { + if (data == null) { + data = new float[this.data.length]; + } else if (data.length < this.data.length) { + throw new IllegalArgumentException("Data array too small (should be " + this.data.length + " but is " + data.length + " )"); + } + System.arraycopy(this.data, 0, data, 0, this.data.length); + return data; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/convolution/LinearKernel.java b/src/main/java/com/sk89q/worldedit/math/convolution/LinearKernel.java new file mode 100644 index 0000000..386b3ff --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/convolution/LinearKernel.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.convolution; + +import java.util.Arrays; + +/** + * A linear Kernel generator (all cells weigh the same). + */ +public class LinearKernel extends Kernel { + + public LinearKernel(int radius) { + super(radius * 2 + 1, radius * 2 + 1, createKernel(radius)); + } + + private static float[] createKernel(int radius) { + int diameter = radius * 2 + 1; + float[] data = new float[diameter * diameter]; + + Arrays.fill(data, 1.0f / data.length); + + return data; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/geom/Polygons.java b/src/main/java/com/sk89q/worldedit/math/geom/Polygons.java new file mode 100644 index 0000000..ae14589 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/geom/Polygons.java @@ -0,0 +1,63 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.geom; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.Vector2; + +import java.util.ArrayList; +import java.util.List; + +/** + * Helper method for anything related to polygons. + */ +public final class Polygons { + + private Polygons() { + } + + /** + * Calculates the polygon shape of a cylinder which can then be used for e.g. intersection detection. + * + * @param center the center point of the cylinder + * @param radius the radius of the cylinder + * @param maxPoints max points to be used for the calculation + * @return a list of {@link BlockVector2} which resemble the shape as a polygon + */ + public static List polygonizeCylinder(BlockVector2 center, Vector2 radius, int maxPoints) { + int nPoints = (int) Math.ceil(Math.PI * radius.length()); + + // These strange semantics for maxPoints are copied from the selectSecondary method. + if (maxPoints >= 0 && nPoints >= maxPoints) { + nPoints = maxPoints - 1; + } + + final List points = new ArrayList<>(nPoints); + for (int i = 0; i < nPoints; ++i) { + double angle = i * (2.0 * Math.PI) / nPoints; + final Vector2 pos = Vector2.at(Math.cos(angle), Math.sin(angle)); + final BlockVector2 blockVector2D = pos.multiply(radius).toBlockPoint().add(center); + points.add(blockVector2D); + } + + return points; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/interpolation/Interpolation.java b/src/main/java/com/sk89q/worldedit/math/interpolation/Interpolation.java new file mode 100644 index 0000000..7acc25f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/interpolation/Interpolation.java @@ -0,0 +1,76 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.math.interpolation; + +import com.sk89q.worldedit.math.Vector3; + +import java.util.List; + +/** + * Represents an arbitrary function in ℝ → ℝ3. + */ +public interface Interpolation { + + /** + * Sets nodes to be used by subsequent calls to + * {@link #getPosition(double)} and the other methods. + * + * @param nodes the nodes + */ + void setNodes(List nodes); + + /** + * Gets the result of f(position). + * + * @param position the position to interpolate + * @return the result + */ + Vector3 getPosition(double position); + + /** + * Gets the result of f'(position). + * + * @param position the position to interpolate + * @return the result + */ + Vector3 get1stDerivative(double position); + + /** + * Gets the result of ∫ab|f'(t)| dt.
+ * That means it calculates the arc length (in meters) between positionA + * and positionB. + * + * @param positionA lower limit + * @param positionB upper limit + * @return the arc length + */ + double arcLength(double positionA, double positionB); + + /** + * Get the segment position. + * + * @param position the position + * @return the segment position + */ + int getSegment(double position); + +} diff --git a/src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java b/src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java new file mode 100644 index 0000000..df5672b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java @@ -0,0 +1,261 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.math.interpolation; + +import com.sk89q.worldedit.math.Vector3; + +import java.util.Collections; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A Kochanek-Bartels interpolation; continuous in the 2nd derivative. + * + *

Supports {@link Node#getTension() tension}, {@link Node#getBias() bias} and + * {@link Node#getContinuity() continuity} parameters per {@link Node}.

+ */ +public class KochanekBartelsInterpolation implements Interpolation { + + private List nodes; + private Vector3[] coeffA; + private Vector3[] coeffB; + private Vector3[] coeffC; + private Vector3[] coeffD; + private double scaling; + + public KochanekBartelsInterpolation() { + setNodes(Collections.emptyList()); + } + + @Override + public void setNodes(List nodes) { + checkNotNull(nodes); + + this.nodes = nodes; + recalc(); + } + + private void recalc() { + final int nNodes = nodes.size(); + coeffA = new Vector3[nNodes]; + coeffB = new Vector3[nNodes]; + coeffC = new Vector3[nNodes]; + coeffD = new Vector3[nNodes]; + + if (nNodes == 0) { + return; + } + + Node nodeB = nodes.get(0); + double tensionB = nodeB.getTension(); + double biasB = nodeB.getBias(); + double continuityB = nodeB.getContinuity(); + for (int i = 0; i < nNodes; ++i) { + final double tensionA = tensionB; + final double biasA = biasB; + final double continuityA = continuityB; + + if (i + 1 < nNodes) { + nodeB = nodes.get(i + 1); + tensionB = nodeB.getTension(); + biasB = nodeB.getBias(); + continuityB = nodeB.getContinuity(); + } + + // Kochanek-Bartels tangent coefficients + final double ta = (1 - tensionA) * (1 + biasA) * (1 + continuityA) / 2; // Factor for lhs of d[i] + final double tb = (1 - tensionA) * (1 - biasA) * (1 - continuityA) / 2; // Factor for rhs of d[i] + final double tc = (1 - tensionB) * (1 + biasB) * (1 - continuityB) / 2; // Factor for lhs of d[i+1] + final double td = (1 - tensionB) * (1 - biasB) * (1 + continuityB) / 2; // Factor for rhs of d[i+1] + + coeffA[i] = linearCombination(i, -ta, ta - tb - tc + 2, tb + tc - td - 2, td); + coeffB[i] = linearCombination(i, 2 * ta, -2 * ta + 2 * tb + tc - 3, -2 * tb - tc + td + 3, -td); + coeffC[i] = linearCombination(i, -ta, ta - tb, tb, 0); + //coeffD[i] = linearCombination(i, 0, 1, 0, 0); + coeffD[i] = retrieve(i); // this is an optimization + } + + scaling = nodes.size() - 1; + } + + /** + * Returns the linear combination of the given coefficients with the nodes adjacent to baseIndex. + * + * @param baseIndex node index + * @param f1 coefficient for baseIndex-1 + * @param f2 coefficient for baseIndex + * @param f3 coefficient for baseIndex+1 + * @param f4 coefficient for baseIndex+2 + * @return linear combination of nodes[n-1..n+2] with f1..4 + */ + private Vector3 linearCombination(int baseIndex, double f1, double f2, double f3, double f4) { + final Vector3 r1 = retrieve(baseIndex - 1).multiply(f1); + final Vector3 r2 = retrieve(baseIndex ).multiply(f2); + final Vector3 r3 = retrieve(baseIndex + 1).multiply(f3); + final Vector3 r4 = retrieve(baseIndex + 2).multiply(f4); + + return r1.add(r2).add(r3).add(r4); + } + + /** + * Retrieves a node. Indexes are clamped to the valid range. + * + * @param index node index to retrieve + * @return nodes[clamp(0, nodes.length-1)] + */ + private Vector3 retrieve(int index) { + if (index < 0) { + return fastRetrieve(0); + } + + if (index >= nodes.size()) { + return fastRetrieve(nodes.size() - 1); + } + + return fastRetrieve(index); + } + + private Vector3 fastRetrieve(int index) { + return nodes.get(index).getPosition(); + } + + @Override + public Vector3 getPosition(double position) { + if (coeffA == null) { + throw new IllegalStateException("Must call setNodes first."); + } + + if (position > 1) { + return null; + } + + position *= scaling; + + final int index = (int) Math.floor(position); + final double remainder = position - index; + + final Vector3 a = coeffA[index]; + final Vector3 b = coeffB[index]; + final Vector3 c = coeffC[index]; + final Vector3 d = coeffD[index]; + + return a.multiply(remainder).add(b).multiply(remainder).add(c).multiply(remainder).add(d); + } + + @Override + public Vector3 get1stDerivative(double position) { + if (coeffA == null) { + throw new IllegalStateException("Must call setNodes first."); + } + + if (position > 1) { + return null; + } + + position *= scaling; + + final int index = (int) Math.floor(position); + //final double remainder = position - index; + + final Vector3 a = coeffA[index]; + final Vector3 b = coeffB[index]; + final Vector3 c = coeffC[index]; + + return a.multiply(1.5 * position - 3.0 * index).add(b).multiply(2.0 * position).add(a.multiply(1.5 * index).subtract(b).multiply(2.0 * index)).add(c).multiply(scaling); + } + + @Override + public double arcLength(double positionA, double positionB) { + if (coeffA == null) { + throw new IllegalStateException("Must call setNodes first."); + } + + if (positionA > positionB) { + return arcLength(positionB, positionA); + } + + positionA *= scaling; + positionB *= scaling; + + final int indexA = (int) Math.floor(positionA); + final double remainderA = positionA - indexA; + + final int indexB = (int) Math.floor(positionB); + final double remainderB = positionB - indexB; + + return arcLengthRecursive(indexA, remainderA, indexB, remainderB); + } + + /** + * Assumes a < b. + */ + private double arcLengthRecursive(int indexLeft, double remainderLeft, int indexRight, double remainderRight) { + switch (indexRight - indexLeft) { + case 0: + return arcLengthRecursive(indexLeft, remainderLeft, remainderRight); + + case 1: + // This case is merely a speed-up for a very common case + return arcLengthRecursive(indexLeft, remainderLeft, 1.0) + + arcLengthRecursive(indexRight, 0.0, remainderRight); + + default: + return arcLengthRecursive(indexLeft, remainderLeft, indexRight - 1, 1.0) + + arcLengthRecursive(indexRight, 0.0, remainderRight); + } + } + + private double arcLengthRecursive(int index, double remainderLeft, double remainderRight) { + final Vector3 a = coeffA[index].multiply(3.0); + final Vector3 b = coeffB[index].multiply(2.0); + final Vector3 c = coeffC[index]; + + final int nPoints = 8; + + double accum = a.multiply(remainderLeft).add(b).multiply(remainderLeft).add(c).length() / 2.0; + for (int i = 1; i < nPoints - 1; ++i) { + double t = ((double) i) / nPoints; + t = (remainderRight - remainderLeft) * t + remainderLeft; + accum += a.multiply(t).add(b).multiply(t).add(c).length(); + } + + accum += a.multiply(remainderRight).add(b).multiply(remainderRight).add(c).length() / 2.0; + return accum * (remainderRight - remainderLeft) / nPoints; + } + + @Override + public int getSegment(double position) { + if (coeffA == null) { + throw new IllegalStateException("Must call setNodes first."); + } + + if (position > 1) { + return Integer.MAX_VALUE; + } + + position *= scaling; + + return (int) Math.floor(position); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/interpolation/LinearInterpolation.java b/src/main/java/com/sk89q/worldedit/math/interpolation/LinearInterpolation.java new file mode 100644 index 0000000..54c700e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/interpolation/LinearInterpolation.java @@ -0,0 +1,163 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.math.interpolation; + +import com.sk89q.worldedit.math.Vector3; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Simple linear interpolation. Mainly used for testing. + */ +public class LinearInterpolation implements Interpolation { + + private List nodes; + + @Override + public void setNodes(List nodes) { + checkNotNull(nodes); + + this.nodes = nodes; + } + + @Override + public Vector3 getPosition(double position) { + if (nodes == null) { + throw new IllegalStateException("Must call setNodes first."); + } + + if (position > 1) { + return null; + } + + position *= nodes.size() - 1; + + final int index1 = (int) Math.floor(position); + final double remainder = position - index1; + + final Vector3 position1 = nodes.get(index1).getPosition(); + final Vector3 position2 = nodes.get(index1 + 1).getPosition(); + + return position1.multiply(1.0 - remainder).add(position2.multiply(remainder)); + } + + /* + Formula for position: + p1*(1-t) + p2*t + Formula for position in Horner/monomial form: + (p2-p1)*t + p1 + 1st Derivative: + p2-p1 + 2nd Derivative: + 0 + Integral: + (p2-p1)/2*t^2 + p1*t + constant + Integral in Horner form: + ((p2-p1)/2*t + p1)*t + constant + */ + + @Override + public Vector3 get1stDerivative(double position) { + if (nodes == null) { + throw new IllegalStateException("Must call setNodes first."); + } + + if (position > 1) { + return null; + } + + position *= nodes.size() - 1; + + final int index1 = (int) Math.floor(position); + + final Vector3 position1 = nodes.get(index1).getPosition(); + final Vector3 position2 = nodes.get(index1 + 1).getPosition(); + + return position2.subtract(position1); + } + + @Override + public double arcLength(double positionA, double positionB) { + if (nodes == null) { + throw new IllegalStateException("Must call setNodes first."); + } + + if (positionA > positionB) { + return arcLength(positionB, positionA); + } + + positionA *= nodes.size() - 1; + positionB *= nodes.size() - 1; + + final int indexA = (int) Math.floor(positionA); + final double remainderA = positionA - indexA; + + final int indexB = (int) Math.floor(positionB); + final double remainderB = positionB - indexB; + + return arcLengthRecursive(indexA, remainderA, indexB, remainderB); + } + + /** + * Assumes a < b. + */ + private double arcLengthRecursive(int indexA, double remainderA, int indexB, double remainderB) { + switch (indexB - indexA) { + case 0: + return arcLengthRecursive(indexA, remainderA, remainderB); + + case 1: + // This case is merely a speed-up for a very common case + return arcLengthRecursive(indexA, remainderA, 1.0) + + arcLengthRecursive(indexB, 0.0, remainderB); + + default: + return arcLengthRecursive(indexA, remainderA, indexB - 1, 1.0) + + arcLengthRecursive(indexB, 0.0, remainderB); + } + } + + private double arcLengthRecursive(int index, double remainderA, double remainderB) { + final Vector3 position1 = nodes.get(index).getPosition(); + final Vector3 position2 = nodes.get(index + 1).getPosition(); + + return position1.distance(position2) * (remainderB - remainderA); + } + + @Override + public int getSegment(double position) { + if (nodes == null) { + throw new IllegalStateException("Must call setNodes first."); + } + + if (position > 1) { + return Integer.MAX_VALUE; + } + + position *= nodes.size() - 1; + + return (int) Math.floor(position); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/interpolation/Node.java b/src/main/java/com/sk89q/worldedit/math/interpolation/Node.java new file mode 100644 index 0000000..d9fcf96 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/interpolation/Node.java @@ -0,0 +1,89 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.math.interpolation; + +import com.sk89q.worldedit.math.Vector3; + +/** + * Represents a node for interpolation. + * + *

The {@link #tension}, {@link #bias} and {@link #continuity} fields + * are parameters for the Kochanek-Bartels interpolation algorithm.

+ */ +public class Node { + + private Vector3 position; + + private double tension; + private double bias; + private double continuity; + + public Node() { + this(Vector3.ZERO); + } + + public Node(Node other) { + this.position = other.position; + + this.tension = other.tension; + this.bias = other.bias; + this.continuity = other.continuity; + } + + public Node(Vector3 position) { + this.position = position; + } + + + public Vector3 getPosition() { + return position; + } + + public void setPosition(Vector3 position) { + this.position = position; + } + + public double getTension() { + return tension; + } + + public void setTension(double tension) { + this.tension = tension; + } + + public double getBias() { + return bias; + } + + public void setBias(double bias) { + this.bias = bias; + } + + public double getContinuity() { + return continuity; + } + + public void setContinuity(double continuity) { + this.continuity = continuity; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/interpolation/ReparametrisingInterpolation.java b/src/main/java/com/sk89q/worldedit/math/interpolation/ReparametrisingInterpolation.java new file mode 100644 index 0000000..8620934 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/interpolation/ReparametrisingInterpolation.java @@ -0,0 +1,166 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.math.interpolation; + +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.Vector3; +import org.apache.logging.log4j.Logger; + +import java.util.List; +import java.util.Map.Entry; +import java.util.TreeMap; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Reparametrises another interpolation function by arc length. + * + *

This is done so entities travel at roughly the same speed across + * the whole route.

+ */ +public class ReparametrisingInterpolation implements Interpolation { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final Interpolation baseInterpolation; + private double totalArcLength; + private final TreeMap cache = new TreeMap<>(); + + public ReparametrisingInterpolation(Interpolation baseInterpolation) { + checkNotNull(baseInterpolation); + + this.baseInterpolation = baseInterpolation; + } + + @Override + public void setNodes(List nodes) { + checkNotNull(nodes); + + baseInterpolation.setNodes(nodes); + cache.clear(); + cache.put(0.0, 0.0); + cache.put(totalArcLength = baseInterpolation.arcLength(0.0, 1.0), 1.0); + } + + public Interpolation getBaseInterpolation() { + return baseInterpolation; + } + + @Override + public Vector3 getPosition(double position) { + if (position > 1) { + return null; + } + + return baseInterpolation.getPosition(arcToParameter(position)); + } + + @Override + public Vector3 get1stDerivative(double position) { + if (position > 1) { + return null; + } + + return baseInterpolation.get1stDerivative(arcToParameter(position)).normalize().multiply(totalArcLength); + } + + @Override + public double arcLength(double positionA, double positionB) { + return baseInterpolation.arcLength(arcToParameter(positionA), arcToParameter(positionB)); + } + + private double arcToParameter(double arc) { + if (cache.isEmpty()) { + throw new IllegalStateException("Must call setNodes first."); + } + + if (arc > 1) { + arc = 1; + } + arc *= totalArcLength; + + Entry floorEntry = cache.floorEntry(arc); + final double leftArc = floorEntry.getKey(); + final double leftParameter = floorEntry.getValue(); + + if (leftArc == arc) { + return leftParameter; + } + + Entry ceilingEntry = cache.ceilingEntry(arc); + if (ceilingEntry == null) { + LOGGER.warn("Error in arcToParameter: no ceiling entry for " + arc + " found!"); + return 0; + } + final double rightArc = ceilingEntry.getKey(); + final double rightParameter = ceilingEntry.getValue(); + + if (rightArc == arc) { + return rightParameter; + } + + return evaluate(arc, leftArc, leftParameter, rightArc, rightParameter); + } + + private double evaluate(double arc, double leftArc, double leftParameter, double rightArc, double rightParameter) { + double midParameter = 0; + for (int i = 0; i < 10; ++i) { + midParameter = (leftParameter + rightParameter) * 0.5; + //final double midArc = leftArc + baseInterpolation.arcLength(leftParameter, midParameter); + final double midArc = baseInterpolation.arcLength(0, midParameter); + cache.put(midArc, midParameter); + + if (midArc < leftArc) { + return leftParameter; + } + + if (midArc > rightArc) { + return rightParameter; + } + + if (Math.abs(midArc - arc) < 0.01) { + return midParameter; + } + + if (arc < midArc) { + // search between left and mid + rightArc = midArc; + rightParameter = midParameter; + } else { + // search between mid and right + leftArc = midArc; + leftParameter = midParameter; + } + } + return midParameter; + } + + @Override + public int getSegment(double position) { + if (position > 1) { + return Integer.MAX_VALUE; + } + + return baseInterpolation.getSegment(arcToParameter(position)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/noise/JLibNoiseGenerator.java b/src/main/java/com/sk89q/worldedit/math/noise/JLibNoiseGenerator.java new file mode 100644 index 0000000..a7f3fe4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/noise/JLibNoiseGenerator.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.noise; + +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.math.Vector3; +import net.royawesome.jlibnoise.module.Module; + +import java.util.Random; + +abstract class JLibNoiseGenerator implements NoiseGenerator { + + private static final Random RANDOM = new Random(); + private final V module; + + JLibNoiseGenerator() { + module = createModule(); + setSeed(RANDOM.nextInt()); + } + + protected abstract V createModule(); + + protected V getModule() { + return module; + } + + public abstract void setSeed(int seed); + + public abstract int getSeed(); + + @Override + public float noise(Vector2 position) { + return forceRange(module.GetValue(position.getX(), 0, position.getZ())); + } + + @Override + public float noise(Vector3 position) { + return forceRange(module.GetValue(position.getX(), position.getY(), position.getZ())); + } + + private float forceRange(double value) { + return (float) Math.max(0, Math.min(1, value / 2.0 + 0.5)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/noise/NoiseGenerator.java b/src/main/java/com/sk89q/worldedit/math/noise/NoiseGenerator.java new file mode 100644 index 0000000..98a7b9f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/noise/NoiseGenerator.java @@ -0,0 +1,48 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.noise; + +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.math.Vector3; + +/** + * Generates noise in a deterministic or non-deterministic manner. + */ +public interface NoiseGenerator { + + /** + * Get the noise value for the given position. The returned value may + * change on every future call for the same position. + * + * @param position the position + * @return a noise value between 0 (inclusive) and 1 (inclusive) + */ + float noise(Vector2 position); + + /** + * Get the noise value for the given position. The returned value may + * change on every future call for the same position. + * + * @param position the position + * @return a noise value between 0 (inclusive) and 1 (inclusive) + */ + float noise(Vector3 position); + +} diff --git a/src/main/java/com/sk89q/worldedit/math/noise/PerlinNoise.java b/src/main/java/com/sk89q/worldedit/math/noise/PerlinNoise.java new file mode 100644 index 0000000..bf0f349 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/noise/PerlinNoise.java @@ -0,0 +1,76 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.noise; + +import net.royawesome.jlibnoise.module.source.Perlin; + +/** + * Generates Perlin noise. + */ +public class PerlinNoise extends JLibNoiseGenerator { + + @Override + protected Perlin createModule() { + return new Perlin(); + } + + public double getFrequency() { + return getModule().getFrequency(); + } + + public void setFrequency(double frequency) { + getModule().setFrequency(frequency); + } + + public double getLacunarity() { + return getModule().getLacunarity(); + } + + public void setLacunarity(double lacunarity) { + getModule().setLacunarity(lacunarity); + } + + public int getOctaveCount() { + return getModule().getOctaveCount(); + } + + public void setOctaveCount(int octaveCount) { + getModule().setOctaveCount(octaveCount); + } + + public void setPersistence(double persistence) { + getModule().setPersistence(persistence); + } + + public double getPersistence() { + return getModule().getPersistence(); + } + + @Override + public void setSeed(int seed) { + getModule().setSeed(seed); + } + + @Override + public int getSeed() { + return getModule().getSeed(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/noise/RandomNoise.java b/src/main/java/com/sk89q/worldedit/math/noise/RandomNoise.java new file mode 100644 index 0000000..7e2bff5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/noise/RandomNoise.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.noise; + +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.math.Vector3; + +import java.util.Random; + +/** + * Generates noise using {@link Random}. Every time a noise + * generating function is called, a new value will be returned. + */ +public class RandomNoise implements NoiseGenerator { + + private final Random random; + + /** + * Create a new noise generator using the given {@code Random}. + * + * @param random the random instance + */ + public RandomNoise(Random random) { + this.random = random; + } + + /** + * Create a new noise generator with a newly constructed {@code Random} + * instance. + */ + public RandomNoise() { + this(new Random()); + } + + @Override + public float noise(Vector2 position) { + return random.nextFloat(); + } + + @Override + public float noise(Vector3 position) { + return random.nextFloat(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/noise/RidgedMultiFractalNoise.java b/src/main/java/com/sk89q/worldedit/math/noise/RidgedMultiFractalNoise.java new file mode 100644 index 0000000..fdfb446 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/noise/RidgedMultiFractalNoise.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.noise; + +import net.royawesome.jlibnoise.module.source.RidgedMulti; + +/** + * Generates ridged multi-fractal noise. + */ +public class RidgedMultiFractalNoise extends JLibNoiseGenerator { + + @Override + protected RidgedMulti createModule() { + return new RidgedMulti(); + } + + public double getFrequency() { + return getModule().getFrequency(); + } + + public void setFrequency(double frequency) { + getModule().setFrequency(frequency); + } + + public double getLacunarity() { + return getModule().getLacunarity(); + } + + public void setLacunarity(double lacunarity) { + getModule().setLacunarity(lacunarity); + } + + public int getOctaveCount() { + return getModule().getOctaveCount(); + } + + public void setOctaveCount(int octaveCount) { + getModule().setOctaveCount(octaveCount); + } + + @Override + public void setSeed(int seed) { + getModule().setSeed(seed); + } + + @Override + public int getSeed() { + return getModule().getSeed(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/noise/VoronoiNoise.java b/src/main/java/com/sk89q/worldedit/math/noise/VoronoiNoise.java new file mode 100644 index 0000000..35de40e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/noise/VoronoiNoise.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.noise; + +import net.royawesome.jlibnoise.module.source.Voronoi; + +/** + * Generates Voronoi noise. + */ +public class VoronoiNoise extends JLibNoiseGenerator { + + @Override + protected Voronoi createModule() { + return new Voronoi(); + } + + public double getFrequency() { + return getModule().getFrequency(); + } + + public void setFrequency(double frequency) { + getModule().setFrequency(frequency); + } + + @Override + public void setSeed(int seed) { + getModule().setSeed(seed); + } + + @Override + public int getSeed() { + return getModule().getSeed(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java new file mode 100644 index 0000000..85422de --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java @@ -0,0 +1,325 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.transform; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MathUtils; +import com.sk89q.worldedit.math.Vector3; + +/** + * An affine transform. + * + *

This class is from the + * JavaGeom project, + * which is licensed under LGPL v2.1.

+ */ +public class AffineTransform implements Transform { + + /** + * coefficients for x coordinate. + */ + private final double m00; + private final double m01; + private final double m02; + private final double m03; + + /** + * coefficients for y coordinate. + */ + private final double m10; + private final double m11; + private final double m12; + private final double m13; + + /** + * coefficients for z coordinate. + */ + private final double m20; + private final double m21; + private final double m22; + private final double m23; + + // =================================================================== + // constructors + + /** + * Creates a new affine transform3D set to the identity. + */ + public AffineTransform() { + // init to identity matrix + m00 = m11 = m22 = 1; + m01 = m02 = m03 = 0; + m10 = m12 = m13 = 0; + m20 = m21 = m23 = 0; + } + + public AffineTransform(double[] coefs) { + if (coefs.length == 9) { + m00 = coefs[0]; + m01 = coefs[1]; + m02 = coefs[2]; + m10 = coefs[3]; + m11 = coefs[4]; + m12 = coefs[5]; + m20 = coefs[6]; + m21 = coefs[7]; + m22 = coefs[8]; + m03 = m13 = m23 = 0; + } else if (coefs.length == 12) { + m00 = coefs[0]; + m01 = coefs[1]; + m02 = coefs[2]; + m03 = coefs[3]; + m10 = coefs[4]; + m11 = coefs[5]; + m12 = coefs[6]; + m13 = coefs[7]; + m20 = coefs[8]; + m21 = coefs[9]; + m22 = coefs[10]; + m23 = coefs[11]; + } else { + throw new IllegalArgumentException( + "Input array must have 9 or 12 elements"); + } + } + + public AffineTransform(double xx, double yx, double zx, double tx, + double xy, double yy, double zy, double ty, double xz, double yz, + double zz, double tz) { + m00 = xx; + m01 = yx; + m02 = zx; + m03 = tx; + m10 = xy; + m11 = yy; + m12 = zy; + m13 = ty; + m20 = xz; + m21 = yz; + m22 = zz; + m23 = tz; + } + + // =================================================================== + // accessors + + @Override + public boolean isIdentity() { + return m00 == m11 && m11 == m22 && m22 == 1 + && m01 == m02 && m02 == m03 && m03 == 0 + && m10 == m12 && m12 == m13 && m13 == 0 + && m20 == m21 && m21 == m23 && m23 == 0; + } + + /** + * Returns the affine coefficients of the transform. Result is an array of + * 12 double. + */ + public double[] coefficients() { + return new double[]{m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23}; + } + + /** + * Computes the determinant of this transform. Can be zero. + * + * @return the determinant of the transform. + */ + private double determinant() { + return m00 * (m11 * m22 - m12 * m21) - m01 * (m10 * m22 - m20 * m12) + + m02 * (m10 * m21 - m20 * m11); + } + + /** + * Computes the inverse affine transform. + */ + @Override + public AffineTransform inverse() { + double det = this.determinant(); + return new AffineTransform( + (m11 * m22 - m21 * m12) / det, + (m21 * m02 - m01 * m22) / det, + (m01 * m12 - m11 * m02) / det, + (m01 * (m22 * m13 - m12 * m23) + m02 * (m11 * m23 - m21 * m13) + - m03 * (m11 * m22 - m21 * m12)) / det, + (m20 * m12 - m10 * m22) / det, + (m00 * m22 - m20 * m02) / det, + (m10 * m02 - m00 * m12) / det, + (m00 * (m12 * m23 - m22 * m13) - m02 * (m10 * m23 - m20 * m13) + + m03 * (m10 * m22 - m20 * m12)) / det, + (m10 * m21 - m20 * m11) / det, + (m20 * m01 - m00 * m21) / det, + (m00 * m11 - m10 * m01) / det, + (m00 * (m21 * m13 - m11 * m23) + m01 * (m10 * m23 - m20 * m13) + - m03 * (m10 * m21 - m20 * m11)) / det); + } + + // =================================================================== + // general methods + + /** + * Returns the affine transform created by applying first the affine + * transform given by {@code that}, then this affine transform. + * + * @param that the transform to apply first + * @return the composition this * that + */ + public AffineTransform concatenate(AffineTransform that) { + double n00 = m00 * that.m00 + m01 * that.m10 + m02 * that.m20; + double n01 = m00 * that.m01 + m01 * that.m11 + m02 * that.m21; + double n02 = m00 * that.m02 + m01 * that.m12 + m02 * that.m22; + double n03 = m00 * that.m03 + m01 * that.m13 + m02 * that.m23 + m03; + double n10 = m10 * that.m00 + m11 * that.m10 + m12 * that.m20; + double n11 = m10 * that.m01 + m11 * that.m11 + m12 * that.m21; + double n12 = m10 * that.m02 + m11 * that.m12 + m12 * that.m22; + double n13 = m10 * that.m03 + m11 * that.m13 + m12 * that.m23 + m13; + double n20 = m20 * that.m00 + m21 * that.m10 + m22 * that.m20; + double n21 = m20 * that.m01 + m21 * that.m11 + m22 * that.m21; + double n22 = m20 * that.m02 + m21 * that.m12 + m22 * that.m22; + double n23 = m20 * that.m03 + m21 * that.m13 + m22 * that.m23 + m23; + return new AffineTransform( + n00, n01, n02, n03, + n10, n11, n12, n13, + n20, n21, n22, n23); + } + + /** + * Return the affine transform created by applying first this affine + * transform, then the affine transform given by {@code that}. + * + * @param that the transform to apply in a second step + * @return the composition that * this + */ + public AffineTransform preConcatenate(AffineTransform that) { + double n00 = that.m00 * m00 + that.m01 * m10 + that.m02 * m20; + double n01 = that.m00 * m01 + that.m01 * m11 + that.m02 * m21; + double n02 = that.m00 * m02 + that.m01 * m12 + that.m02 * m22; + double n03 = that.m00 * m03 + that.m01 * m13 + that.m02 * m23 + that.m03; + double n10 = that.m10 * m00 + that.m11 * m10 + that.m12 * m20; + double n11 = that.m10 * m01 + that.m11 * m11 + that.m12 * m21; + double n12 = that.m10 * m02 + that.m11 * m12 + that.m12 * m22; + double n13 = that.m10 * m03 + that.m11 * m13 + that.m12 * m23 + that.m13; + double n20 = that.m20 * m00 + that.m21 * m10 + that.m22 * m20; + double n21 = that.m20 * m01 + that.m21 * m11 + that.m22 * m21; + double n22 = that.m20 * m02 + that.m21 * m12 + that.m22 * m22; + double n23 = that.m20 * m03 + that.m21 * m13 + that.m22 * m23 + that.m23; + return new AffineTransform( + n00, n01, n02, n03, + n10, n11, n12, n13, + n20, n21, n22, n23); + } + + public AffineTransform translate(Vector3 vec) { + return translate(vec.getX(), vec.getY(), vec.getZ()); + } + + public AffineTransform translate(BlockVector3 vec) { + return translate(vec.getX(), vec.getY(), vec.getZ()); + } + + public AffineTransform translate(double x, double y, double z) { + return concatenate(new AffineTransform(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z)); + } + + public AffineTransform rotateX(double theta) { + double cot = MathUtils.dCos(theta); + double sit = MathUtils.dSin(theta); + return concatenate( + new AffineTransform( + 1, 0, 0, 0, + 0, cot, -sit, 0, + 0, sit, cot, 0)); + } + + public AffineTransform rotateY(double theta) { + double cot = MathUtils.dCos(theta); + double sit = MathUtils.dSin(theta); + return concatenate( + new AffineTransform( + cot, 0, sit, 0, + 0, 1, 0, 0, + -sit, 0, cot, 0)); + } + + public AffineTransform rotateZ(double theta) { + double cot = MathUtils.dCos(theta); + double sit = MathUtils.dSin(theta); + return concatenate( + new AffineTransform( + cot, -sit, 0, 0, + sit, cot, 0, 0, + 0, 0, 1, 0)); + } + + public AffineTransform scale(double s) { + return scale(s, s, s); + } + + public AffineTransform scale(double sx, double sy, double sz) { + return concatenate(new AffineTransform(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0)); + } + + public AffineTransform scale(Vector3 vec) { + return scale(vec.getX(), vec.getY(), vec.getZ()); + } + + @Override + public Vector3 apply(Vector3 vector) { + return Vector3.at( + vector.getX() * m00 + vector.getY() * m01 + vector.getZ() * m02 + m03, + vector.getX() * m10 + vector.getY() * m11 + vector.getZ() * m12 + m13, + vector.getX() * m20 + vector.getY() * m21 + vector.getZ() * m22 + m23); + } + + public AffineTransform combine(AffineTransform other) { + return concatenate(other); + } + + @Override + public Transform combine(Transform other) { + if (other instanceof AffineTransform) { + return concatenate((AffineTransform) other); + } else { + return new CombinedTransform(this, other); + } + } + + /** + * Returns if this affine transform represents a horizontal flip. + */ + public boolean isHorizontalFlip() { + // use the determinant of the x-z submatrix to check if this is a horizontal flip + return m00 * m22 - m02 * m20 < 0; + } + + /** + * Returns if this affine transform represents a vertical flip. + */ + public boolean isVerticalFlip() { + return m11 < 0; + } + + @Override + public String toString() { + return String.format("Affine[%g %g %g %g, %g %g %g %g, %g %g %g %g]}", m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23); + } + + +} diff --git a/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java b/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java new file mode 100644 index 0000000..6cac508 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java @@ -0,0 +1,99 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.transform; + +import com.sk89q.worldedit.math.Vector3; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Combines several transforms in order. + */ +public class CombinedTransform implements Transform { + + private final Transform[] transforms; + + /** + * Create a new combined transformation. + * + * @param transforms a list of transformations + */ + public CombinedTransform(Transform... transforms) { + checkNotNull(transforms); + this.transforms = Arrays.copyOf(transforms, transforms.length); + } + + /** + * Create a new combined transformation. + * + * @param transforms a list of transformations + */ + public CombinedTransform(Collection transforms) { + this(transforms.toArray(new Transform[checkNotNull(transforms).size()])); + } + + @Override + public boolean isIdentity() { + for (Transform transform : transforms) { + if (!transform.isIdentity()) { + return false; + } + } + + return true; + } + + @Override + public Vector3 apply(Vector3 vector) { + for (Transform transform : transforms) { + vector = transform.apply(vector); + } + return vector; + } + + @Override + public Transform inverse() { + List list = new ArrayList<>(); + for (int i = transforms.length - 1; i >= 0; i--) { + list.add(transforms[i].inverse()); + } + return new CombinedTransform(list); + } + + @Override + public Transform combine(Transform other) { + checkNotNull(other); + if (other instanceof CombinedTransform) { + CombinedTransform combinedOther = (CombinedTransform) other; + Transform[] newTransforms = new Transform[transforms.length + combinedOther.transforms.length]; + System.arraycopy(transforms, 0, newTransforms, 0, transforms.length); + System.arraycopy(combinedOther.transforms, 0, newTransforms, transforms.length, combinedOther.transforms.length); + return new CombinedTransform(newTransforms); + } else { + return new CombinedTransform(this, other); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/transform/Identity.java b/src/main/java/com/sk89q/worldedit/math/transform/Identity.java new file mode 100644 index 0000000..d4efde9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/transform/Identity.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.transform; + +import com.sk89q.worldedit.math.Vector3; + +/** + * Makes no transformation to given vectors. + */ +public class Identity implements Transform { + + @Override + public boolean isIdentity() { + return true; + } + + @Override + public Vector3 apply(Vector3 vector) { + return vector; + } + + @Override + public Transform inverse() { + return this; + } + + @Override + public Transform combine(Transform other) { + if (other instanceof Identity) { + return this; + } else { + return other; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/transform/Transform.java b/src/main/java/com/sk89q/worldedit/math/transform/Transform.java new file mode 100644 index 0000000..d108add --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/transform/Transform.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.transform; + +import com.sk89q.worldedit.math.Vector3; + +/** + * Makes a transformation of {@link Vector3}s. + */ +public interface Transform { + + /** + * Return whether this transform is an identity. + * + *

If it is not known, then {@code false} must be returned.

+ * + * @return true if identity + */ + boolean isIdentity(); + + /** + * Returns the result of applying the function to the input. + * + * @param input the input + * @return the result + */ + Vector3 apply(Vector3 input); + + /** + * Create a new inverse transform. + * + * @return a new inverse transform + */ + Transform inverse(); + + /** + * Create a new {@link Transform} that combines this transform with another. + * + * @param other the other transform to occur second + * @return a new transform + */ + Transform combine(Transform other); + +} diff --git a/src/main/java/com/sk89q/worldedit/math/transform/Transforms.java b/src/main/java/com/sk89q/worldedit/math/transform/Transforms.java new file mode 100644 index 0000000..aee8308 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/transform/Transforms.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.math.transform; + +import com.sk89q.worldedit.util.Location; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Various utility methods related to {@link Transform}s. + */ +public final class Transforms { + + private Transforms() { + } + + /** + * Transform a location's position with a given transform. + * + *

Direction is unaffected.

+ * + * @param location the location + * @param transform the transform + * @return the transformed location + */ + public static Location transform(Location location, Transform transform) { + checkNotNull(location); + checkNotNull(transform); + return new Location(location.getExtent(), transform.apply(location.toVector()), location.getDirection()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java b/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java new file mode 100644 index 0000000..8534f0f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.world.World; + +public abstract class AbstractFlatRegion extends AbstractRegion implements FlatRegion { + + protected AbstractFlatRegion(World world) { + super(world); + } + + @Override + public int getMinimumY() { + return getMinimumPoint().getBlockY(); + } + + @Override + public int getMaximumY() { + return getMaximumPoint().getBlockY(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java b/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java new file mode 100644 index 0000000..ed0c7e4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java @@ -0,0 +1,217 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.iterator.RegionIterator; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.storage.ChunkStore; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +public abstract class AbstractRegion implements Region { + + protected World world; + + public AbstractRegion(World world) { + this.world = world; + } + + @Override + public Vector3 getCenter() { + return getMinimumPoint().add(getMaximumPoint()).toVector3().divide(2); + } + + /** + * Get the iterator. + * + * @return iterator of points inside the region + */ + @Override + public Iterator iterator() { + return new RegionIterator(this); + } + + @Override + public World getWorld() { + return world; + } + + @Override + public void setWorld(World world) { + this.world = world; + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + expand(change); + contract(change); + } + + @Override + public AbstractRegion clone() { + try { + return (AbstractRegion) super.clone(); + } catch (CloneNotSupportedException exc) { + return null; + } + } + + @Override + public List polygonize(int maxPoints) { + if (maxPoints >= 0 && maxPoints < 4) { + throw new IllegalArgumentException("Cannot polygonize an AbstractRegion with no overridden polygonize method into less than 4 points."); + } + + final BlockVector3 min = getMinimumPoint(); + final BlockVector3 max = getMaximumPoint(); + + final List points = new ArrayList<>(4); + + points.add(BlockVector2.at(min.getX(), min.getZ())); + points.add(BlockVector2.at(min.getX(), max.getZ())); + points.add(BlockVector2.at(max.getX(), max.getZ())); + points.add(BlockVector2.at(max.getX(), min.getZ())); + + return points; + } + + @Override + public long getVolume() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return (max.getX() - min.getX() + 1L) + * (max.getY() - min.getY() + 1L) + * (max.getZ() - min.getZ() + 1L); + } + + /** + * Get X-size. + * + * @return width + */ + @Override + public int getWidth() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return max.getX() - min.getX() + 1; + } + + /** + * Get Y-size. + * + * @return height + */ + @Override + public int getHeight() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return max.getY() - min.getY() + 1; + } + + /** + * Get Z-size. + * + * @return length + */ + @Override + public int getLength() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return max.getZ() - min.getZ() + 1; + } + + /** + * Get a list of chunks. + * + * @return a set of chunks + */ + @Override + public Set getChunks() { + final Set chunks = new HashSet<>(); + + final BlockVector3 min = getMinimumPoint(); + final BlockVector3 max = getMaximumPoint(); + + final int minY = min.getBlockY(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { + if (!contains(BlockVector3.at(x, minY, z))) { + continue; + } + + chunks.add(BlockVector2.at( + x >> ChunkStore.CHUNK_SHIFTS, + z >> ChunkStore.CHUNK_SHIFTS + )); + } + } + + return chunks; + } + + @Override + public Set getChunkCubes() { + final Set chunks = new HashSet<>(); + + final BlockVector3 min = getMinimumPoint(); + final BlockVector3 max = getMaximumPoint(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { + for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { + if (!contains(BlockVector3.at(x, y, z))) { + continue; + } + + chunks.add(BlockVector3.at( + x >> ChunkStore.CHUNK_SHIFTS, + y >> ChunkStore.CHUNK_SHIFTS, + z >> ChunkStore.CHUNK_SHIFTS + )); + } + } + } + + return chunks; + } + + // Sub-class utilities + + protected final int getWorldMinY() { + return world == null ? Integer.MIN_VALUE : world.getMinY(); + } + + protected final int getWorldMaxY() { + return world == null ? Integer.MAX_VALUE : world.getMaxY(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegion.java b/src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegion.java new file mode 100644 index 0000000..5fa5c53 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegion.java @@ -0,0 +1,331 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.polyhedron.Edge; +import com.sk89q.worldedit.regions.polyhedron.Triangle; +import com.sk89q.worldedit.world.World; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ConvexPolyhedralRegion extends AbstractRegion { + + /** + * Vertices that are contained in the convex hull. + */ + private final Set vertices = new LinkedHashSet<>(); + + /** + * Triangles that form the convex hull. + */ + private final List triangles = new ArrayList<>(); + + /** + * Vertices that are coplanar to the first 3 vertices. + */ + private final Set vertexBacklog = new LinkedHashSet<>(); + + /** + * Minimum point of the axis-aligned bounding box. + */ + private BlockVector3 minimumPoint; + + /** + * Maximum point of the axis-aligned bounding box. + */ + private BlockVector3 maximumPoint; + + /** + * Accumulator for the barycenter of the polyhedron. Divide by vertices.size() to get the actual center. + */ + private BlockVector3 centerAccum = BlockVector3.ZERO; + + /** + * The last triangle that caused a {@link #contains(BlockVector3)}} to classify a point as "outside". Used for optimization. + */ + private Triangle lastTriangle; + + /** + * Constructs an empty mesh, containing no vertices or triangles. + * + * @param world the world + */ + public ConvexPolyhedralRegion(@Nullable World world) { + super(world); + } + + /** + * Constructs an independent copy of the given region. + * + * @param region the region to copy + */ + public ConvexPolyhedralRegion(ConvexPolyhedralRegion region) { + this(region.world); + vertices.addAll(region.vertices); + triangles.addAll(region.triangles); + vertexBacklog.addAll(region.vertexBacklog); + + minimumPoint = region.minimumPoint; + maximumPoint = region.maximumPoint; + centerAccum = region.centerAccum; + lastTriangle = region.lastTriangle; + } + + /** + * Clears the region, removing all vertices and triangles. + */ + public void clear() { + vertices.clear(); + triangles.clear(); + vertexBacklog.clear(); + + minimumPoint = null; + maximumPoint = null; + centerAccum = BlockVector3.ZERO; + lastTriangle = null; + } + + /** + * Add a vertex to the region. + * + * @param vertex the vertex + * @return true, if something changed. + */ + public boolean addVertex(BlockVector3 vertex) { + checkNotNull(vertex); + + lastTriangle = null; // Probably not necessary + + if (vertices.contains(vertex)) { + return false; + } + + Vector3 vertexD = vertex.toVector3(); + + if (vertices.size() == 3) { + if (vertexBacklog.contains(vertex)) { + return false; + } + + if (containsRaw(vertexD)) { + return vertexBacklog.add(vertex); + } + } + + vertices.add(vertex); + + centerAccum = centerAccum.add(vertex); + + if (minimumPoint == null) { + minimumPoint = maximumPoint = vertex; + } else { + minimumPoint = minimumPoint.getMinimum(vertex); + maximumPoint = maximumPoint.getMaximum(vertex); + } + + + switch (vertices.size()) { + case 0: + case 1: + case 2: + // Incomplete, can't make a mesh yet + return true; + + case 3: + // Generate minimal mesh to start from + final BlockVector3[] v = vertices.toArray(new BlockVector3[0]); + + triangles.add((new Triangle(v[0].toVector3(), v[1].toVector3(), v[2].toVector3()))); + triangles.add((new Triangle(v[0].toVector3(), v[2].toVector3(), v[1].toVector3()))); + return true; + + default: + break; + } + + // Look for triangles that face the vertex and remove them + final Set borderEdges = new LinkedHashSet<>(); + for (Iterator it = triangles.iterator(); it.hasNext(); ) { + final Triangle triangle = it.next(); + + // If the triangle can't be seen, it's not relevant + if (!triangle.above(vertexD)) { + continue; + } + + // Remove the triangle from the mesh + it.remove(); + + // ...and remember its edges + for (int i = 0; i < 3; ++i) { + final Edge edge = triangle.getEdge(i); + if (borderEdges.remove(edge)) { + continue; + } + + borderEdges.add(edge); + } + } + + // Add triangles between the remembered edges and the new vertex. + for (Edge edge : borderEdges) { + triangles.add(edge.createTriangle(vertexD)); + } + + if (!vertexBacklog.isEmpty()) { + // Remove the new vertex + vertices.remove(vertex); + + // Clone, clear and work through the backlog + final List vertexBacklog2 = new ArrayList<>(vertexBacklog); + vertexBacklog.clear(); + for (BlockVector3 vertex2 : vertexBacklog2) { + addVertex(vertex2); + } + + // Re-add the new vertex after the backlog. + vertices.add(vertex); + } + + return true; + } + + public boolean isDefined() { + return !triangles.isEmpty(); + } + + @Override + public BlockVector3 getMinimumPoint() { + return minimumPoint; + } + + @Override + public BlockVector3 getMaximumPoint() { + return maximumPoint; + } + + @Override + public Vector3 getCenter() { + return centerAccum.toVector3().divide(vertices.size()); + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + Vector3 vec = change.toVector3(); + shiftCollection(vertices, change); + shiftCollection(vertexBacklog, change); + + for (int i = 0; i < triangles.size(); ++i) { + final Triangle triangle = triangles.get(i); + + final Vector3 v0 = vec.add(triangle.getVertex(0)); + final Vector3 v1 = vec.add(triangle.getVertex(1)); + final Vector3 v2 = vec.add(triangle.getVertex(2)); + + triangles.set(i, new Triangle(v0, v1, v2)); + } + + minimumPoint = change.add(minimumPoint); + maximumPoint = change.add(maximumPoint); + centerAccum = change.multiply(vertices.size()).add(centerAccum); + lastTriangle = null; + } + + private static void shiftCollection(Collection collection, BlockVector3 change) { + final List tmp = new ArrayList<>(collection); + collection.clear(); + for (BlockVector3 vertex : tmp) { + collection.add(change.add(vertex)); + } + } + + @Override + public boolean contains(BlockVector3 position) { + if (!isDefined()) { + return false; + } + + final BlockVector3 min = getMinimumPoint(); + final BlockVector3 max = getMaximumPoint(); + + if (!position.containedWithin(min, max)) { + return false; + } + + return containsRaw(position.toVector3()); + } + + private boolean containsRaw(Vector3 pt) { + if (lastTriangle != null && lastTriangle.above(pt)) { + return false; + } + + for (Triangle triangle : triangles) { + if (lastTriangle == triangle) { + continue; + } + + if (triangle.above(pt)) { + lastTriangle = triangle; + return false; + } + } + + return true; + } + + public Collection getVertices() { + if (vertexBacklog.isEmpty()) { + return vertices; + } + + final List ret = new ArrayList<>(vertices); + ret.addAll(vertexBacklog); + + return ret; + } + + public Collection getTriangles() { + return triangles; + } + + @Override + public AbstractRegion clone() { + return new ConvexPolyhedralRegion(this); + } +} diff --git a/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java new file mode 100644 index 0000000..e7da13c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -0,0 +1,432 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.storage.ChunkStore; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An axis-aligned cuboid. It can be defined using two corners of the cuboid. + */ +public class CuboidRegion extends AbstractRegion implements FlatRegion { + + private BlockVector3 pos1; + private BlockVector3 pos2; + + /** + * Construct a new instance of this cuboid using two corners of the cuboid. + * + * @param pos1 the first position + * @param pos2 the second position + */ + public CuboidRegion(BlockVector3 pos1, BlockVector3 pos2) { + this(null, pos1, pos2); + } + + /** + * Construct a new instance of this cuboid using two corners of the cuboid. + * + * @param world the world + * @param pos1 the first position + * @param pos2 the second position + */ + public CuboidRegion(World world, BlockVector3 pos1, BlockVector3 pos2) { + super(world); + checkNotNull(pos1); + checkNotNull(pos2); + this.pos1 = pos1; + this.pos2 = pos2; + recalculate(); + } + + /** + * Get the first cuboid-defining corner. + * + * @return a position + */ + public BlockVector3 getPos1() { + return pos1; + } + + /** + * Set the first cuboid-defining corner. + * + * @param pos1 a position + */ + public void setPos1(BlockVector3 pos1) { + this.pos1 = pos1; + } + + /** + * Get the second cuboid-defining corner. + * + * @return a position + */ + public BlockVector3 getPos2() { + return pos2; + } + + /** + * Set the second cuboid-defining corner. + * + * @param pos2 a position + */ + public void setPos2(BlockVector3 pos2) { + this.pos2 = pos2; + } + + /** + * Clamps the cuboid according to boundaries of the world. + */ + private void recalculate() { + pos1 = pos1.clampY(getWorldMinY(), getWorldMaxY()); + pos2 = pos2.clampY(getWorldMinY(), getWorldMaxY()); + } + + /** + * Get a region that contains the faces of this cuboid. + * + * @return a new complex region + */ + public Region getFaces() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return new RegionIntersection( + // Project to Z-Y plane + new CuboidRegion(pos1.withX(min.getX()), pos2.withX(min.getX())), + new CuboidRegion(pos1.withX(max.getX()), pos2.withX(max.getX())), + + // Project to X-Y plane + new CuboidRegion(pos1.withZ(min.getZ()), pos2.withZ(min.getZ())), + new CuboidRegion(pos1.withZ(max.getZ()), pos2.withZ(max.getZ())), + + // Project to the X-Z plane + new CuboidRegion(pos1.withY(min.getY()), pos2.withY(min.getY())), + new CuboidRegion(pos1.withY(max.getY()), pos2.withY(max.getY()))); + } + + /** + * Get a region that contains the walls (all faces but the ones parallel to + * the X-Z plane) of this cuboid. + * + * @return a new complex region + */ + public Region getWalls() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return new RegionIntersection( + // Project to Z-Y plane + new CuboidRegion(pos1.withX(min.getX()), pos2.withX(min.getX())), + new CuboidRegion(pos1.withX(max.getX()), pos2.withX(max.getX())), + + // Project to X-Y plane + new CuboidRegion(pos1.withZ(min.getZ()), pos2.withZ(min.getZ())), + new CuboidRegion(pos1.withZ(max.getZ()), pos2.withZ(max.getZ()))); + } + + @Override + public BlockVector3 getMinimumPoint() { + return pos1.getMinimum(pos2); + } + + @Override + public BlockVector3 getMaximumPoint() { + return pos1.getMaximum(pos2); + } + + @Override + public CuboidRegion getBoundingBox() { + return this; + } + + @Override + public int getMinimumY() { + return Math.min(pos1.getBlockY(), pos2.getBlockY()); + } + + @Override + public int getMaximumY() { + return Math.max(pos1.getBlockY(), pos2.getBlockY()); + } + + @Override + public void expand(BlockVector3... changes) { + checkNotNull(changes); + + for (BlockVector3 change : changes) { + if (change.getX() > 0) { + if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) { + pos1 = pos1.add(change.getX(), 0, 0); + } else { + pos2 = pos2.add(change.getX(), 0, 0); + } + } else { + if (Math.min(pos1.getX(), pos2.getX()) == pos1.getX()) { + pos1 = pos1.add(change.getX(), 0, 0); + } else { + pos2 = pos2.add(change.getX(), 0, 0); + } + } + + if (change.getY() > 0) { + if (Math.max(pos1.getY(), pos2.getY()) == pos1.getY()) { + pos1 = pos1.add(0, change.getY(), 0); + } else { + pos2 = pos2.add(0, change.getY(), 0); + } + } else { + if (Math.min(pos1.getY(), pos2.getY()) == pos1.getY()) { + pos1 = pos1.add(0, change.getY(), 0); + } else { + pos2 = pos2.add(0, change.getY(), 0); + } + } + + if (change.getZ() > 0) { + if (Math.max(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { + pos1 = pos1.add(0, 0, change.getZ()); + } else { + pos2 = pos2.add(0, 0, change.getZ()); + } + } else { + if (Math.min(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { + pos1 = pos1.add(0, 0, change.getZ()); + } else { + pos2 = pos2.add(0, 0, change.getZ()); + } + } + } + + recalculate(); + } + + @Override + public void contract(BlockVector3... changes) { + checkNotNull(changes); + + for (BlockVector3 change : changes) { + if (change.getX() < 0) { + if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) { + pos1 = pos1.add(change.getX(), 0, 0); + } else { + pos2 = pos2.add(change.getX(), 0, 0); + } + } else { + if (Math.min(pos1.getX(), pos2.getX()) == pos1.getX()) { + pos1 = pos1.add(change.getX(), 0, 0); + } else { + pos2 = pos2.add(change.getX(), 0, 0); + } + } + + if (change.getY() < 0) { + if (Math.max(pos1.getY(), pos2.getY()) == pos1.getY()) { + pos1 = pos1.add(0, change.getY(), 0); + } else { + pos2 = pos2.add(0, change.getY(), 0); + } + } else { + if (Math.min(pos1.getY(), pos2.getY()) == pos1.getY()) { + pos1 = pos1.add(0, change.getY(), 0); + } else { + pos2 = pos2.add(0, change.getY(), 0); + } + } + + if (change.getZ() < 0) { + if (Math.max(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { + pos1 = pos1.add(0, 0, change.getZ()); + } else { + pos2 = pos2.add(0, 0, change.getZ()); + } + } else { + if (Math.min(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { + pos1 = pos1.add(0, 0, change.getZ()); + } else { + pos2 = pos2.add(0, 0, change.getZ()); + } + } + } + + recalculate(); + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + pos1 = pos1.add(change); + pos2 = pos2.add(change); + + recalculate(); + } + + @Override + public Set getChunks() { + Set chunks = new HashSet<>(); + + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + for (int x = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; x <= max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; ++x) { + for (int z = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; z <= max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; ++z) { + chunks.add(BlockVector2.at(x, z)); + } + } + + return chunks; + } + + @Override + public Set getChunkCubes() { + Set chunks = new HashSet<>(); + + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + for (int x = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; x <= max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; ++x) { + for (int z = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; z <= max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; ++z) { + for (int y = min.getBlockY() >> ChunkStore.CHUNK_SHIFTS; y <= max.getBlockY() >> ChunkStore.CHUNK_SHIFTS; ++y) { + chunks.add(BlockVector3.at(x, y, z)); + } + } + } + + return chunks; + } + + @Override + public boolean contains(BlockVector3 position) { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return position.containedWithin(min, max); + } + + @Override + public Iterator iterator() { + return new Iterator() { + private final BlockVector3 min = getMinimumPoint(); + private final BlockVector3 max = getMaximumPoint(); + private int nextX = min.getBlockX(); + private int nextY = min.getBlockY(); + private int nextZ = min.getBlockZ(); + + @Override + public boolean hasNext() { + return (nextX != Integer.MIN_VALUE); + } + + @Override + public BlockVector3 next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + BlockVector3 answer = BlockVector3.at(nextX, nextY, nextZ); + if (++nextX > max.getBlockX()) { + nextX = min.getBlockX(); + if (++nextZ > max.getBlockZ()) { + nextZ = min.getBlockZ(); + if (++nextY > max.getBlockY()) { + nextX = Integer.MIN_VALUE; + } + } + } + return answer; + } + }; + } + + @Override + public Iterable asFlatRegion() { + return () -> new Iterator() { + private final BlockVector3 min = getMinimumPoint(); + private final BlockVector3 max = getMaximumPoint(); + private int nextX = min.getBlockX(); + private int nextZ = min.getBlockZ(); + + @Override + public boolean hasNext() { + return (nextX != Integer.MIN_VALUE); + } + + @Override + public BlockVector2 next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + BlockVector2 answer = BlockVector2.at(nextX, nextZ); + if (++nextX > max.getBlockX()) { + nextX = min.getBlockX(); + if (++nextZ > max.getBlockZ()) { + nextX = Integer.MIN_VALUE; + } + } + return answer; + } + }; + } + + @Override + public String toString() { + return getMinimumPoint() + " - " + getMaximumPoint(); + } + + @Override + public CuboidRegion clone() { + return (CuboidRegion) super.clone(); + } + + /** + * Make a cuboid region out of the given region using the minimum and maximum + * bounds of the provided region. + * + * @param region the region + * @return a new cuboid region + */ + public static CuboidRegion makeCuboid(Region region) { + checkNotNull(region); + return new CuboidRegion(region.getMinimumPoint(), region.getMaximumPoint()); + } + + /** + * Make a cuboid from the center. + * + * @param origin the origin + * @param apothem the apothem, where 0 is the minimum value to make a 1x1 cuboid + * @return a cuboid region + */ + public static CuboidRegion fromCenter(BlockVector3 origin, int apothem) { + checkNotNull(origin); + checkArgument(apothem >= 0, "apothem => 0 required"); + BlockVector3 size = BlockVector3.ONE.multiply(apothem); + return new CuboidRegion(origin.subtract(size), origin.add(size)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java b/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java new file mode 100644 index 0000000..06adca9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java @@ -0,0 +1,358 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.geom.Polygons; +import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator; +import com.sk89q.worldedit.regions.iterator.FlatRegionIterator; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a cylindrical region. + */ +public class CylinderRegion extends AbstractRegion implements FlatRegion { + + private BlockVector2 center; + private Vector2 radius; + private int minY; + private int maxY; + private boolean hasY = false; + + /** + * Construct the region. + */ + public CylinderRegion() { + this((World) null); + } + + /** + * Construct the region. + * + * @param world the world + */ + public CylinderRegion(World world) { + this(world, BlockVector3.ZERO, Vector2.ZERO, 0, 0); + hasY = false; + } + + /** + * Construct the region. + * + * @param world the world + * @param center the center position + * @param radius the radius along the X and Z axes + * @param minY the minimum Y, inclusive + * @param maxY the maximum Y, inclusive + */ + public CylinderRegion(World world, BlockVector3 center, Vector2 radius, int minY, int maxY) { + super(world); + setCenter(center.toBlockVector2()); + setRadius(radius); + this.minY = minY; + this.maxY = maxY; + hasY = true; + } + + /** + * Construct the region. + * + * @param center the center position + * @param radius the radius along the X and Z axes + * @param minY the minimum Y, inclusive + * @param maxY the maximum Y, inclusive + */ + public CylinderRegion(BlockVector3 center, Vector2 radius, int minY, int maxY) { + super(null); + setCenter(center.toBlockVector2()); + setRadius(radius); + this.minY = minY; + this.maxY = maxY; + hasY = true; + } + + public CylinderRegion(CylinderRegion region) { + this(region.world, region.getCenter().toBlockPoint(), region.getRadius(), region.minY, region.maxY); + hasY = region.hasY; + } + + @Override + public Vector3 getCenter() { + return center.toVector3((maxY + minY) / 2); + } + + /** + * Sets the main center point of the region. + * + * @param center the center point + */ + public void setCenter(BlockVector2 center) { + this.center = center; + } + + /** + * Returns the radius of the cylinder. + * + * @return the radius along the X and Z axes + */ + public Vector2 getRadius() { + return radius.subtract(0.5, 0.5); + } + + /** + * Sets the radius of the cylinder. + * + * @param radius the radius along the X and Z axes + */ + public void setRadius(Vector2 radius) { + this.radius = radius.add(0.5, 0.5); + } + + /** + * Extends the radius to be at least the given radius. + * + * @param minRadius the minimum radius + */ + public void extendRadius(Vector2 minRadius) { + setRadius(minRadius.getMaximum(getRadius())); + } + + /** + * Set the minimum Y. + * + * @param y the y + */ + public void setMinimumY(int y) { + hasY = true; + minY = y; + } + + /** + * Se the maximum Y. + * + * @param y the y + */ + public void setMaximumY(int y) { + hasY = true; + maxY = y; + } + + @Override + public BlockVector3 getMinimumPoint() { + return center.toVector2().subtract(getRadius()).toVector3(minY).toBlockPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return center.toVector2().add(getRadius()).toVector3(maxY).toBlockPoint(); + } + + @Override + public int getMaximumY() { + return maxY; + } + + @Override + public int getMinimumY() { + return minY; + } + + private static final BigDecimal PI = BigDecimal.valueOf(Math.PI); + + @Override + public long getVolume() { + return BigDecimal.valueOf(radius.getX()) + .multiply(BigDecimal.valueOf(radius.getZ())) + .multiply(PI) + .multiply(BigDecimal.valueOf(getHeight())) + .setScale(0, RoundingMode.FLOOR) + .longValue(); + } + + @Override + public int getWidth() { + return (int) (2 * radius.getX()); + } + + @Override + public int getHeight() { + return maxY - minY + 1; + } + + @Override + public int getLength() { + return (int) (2 * radius.getZ()); + } + + private BlockVector2 calculateDiff2D(BlockVector3... changes) throws RegionOperationException { + BlockVector2 diff = BlockVector2.ZERO; + for (BlockVector3 change : changes) { + diff = diff.add(change.toBlockVector2()); + } + + if ((diff.getBlockX() & 1) + (diff.getBlockZ() & 1) != 0) { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.cylinder.error.even-horizontal")); + } + + return diff.divide(2).floor(); + } + + private BlockVector2 calculateChanges2D(BlockVector3... changes) { + BlockVector2 total = BlockVector2.ZERO; + for (BlockVector3 change : changes) { + total = total.add(change.toBlockVector2().abs()); + } + + return total.divide(2).floor(); + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + center = center.add(calculateDiff2D(changes)); + radius = radius.add(calculateChanges2D(changes).toVector2()); + for (BlockVector3 change : changes) { + int changeY = change.getBlockY(); + if (changeY > 0) { + maxY += changeY; + } else { + minY += changeY; + } + } + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + center = center.subtract(calculateDiff2D(changes)); + Vector2 newRadius = radius.subtract(calculateChanges2D(changes).toVector2()); + radius = Vector2.at(1.5, 1.5).getMaximum(newRadius); + for (BlockVector3 change : changes) { + int height = maxY - minY; + int changeY = change.getBlockY(); + if (changeY > 0) { + minY += Math.min(height, changeY); + } else { + maxY += Math.max(-height, changeY); + } + } + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + center = center.add(change.toBlockVector2()); + + int changeY = change.getBlockY(); + maxY += changeY; + minY += changeY; + } + + /** + * Checks to see if a point is inside this region. + */ + @Override + public boolean contains(BlockVector3 position) { + final int blockY = position.getBlockY(); + if (blockY < minY || blockY > maxY) { + return false; + } + + return position.toBlockVector2().subtract(center).toVector2().divide(radius).lengthSq() <= 1; + } + + + /** + * Sets the height of the cylinder to fit the specified Y. + * + * @param y the y value + * @return true if the area was expanded + */ + public boolean setY(int y) { + if (!hasY) { + minY = y; + maxY = y; + hasY = true; + return true; + } else if (y < minY) { + minY = y; + return true; + } else if (y > maxY) { + maxY = y; + return true; + } + + return false; + } + + @Override + public Iterator iterator() { + return new FlatRegion3DIterator(this); + } + + @Override + public Iterable asFlatRegion() { + return () -> new FlatRegionIterator(CylinderRegion.this); + } + + @Override + public String toString() { + return center + " - " + radius + "(" + minY + ", " + maxY + ")"; + } + + @Override + public CylinderRegion clone() { + return (CylinderRegion) super.clone(); + } + + @Override + public List polygonize(int maxPoints) { + return Polygons.polygonizeCylinder(center, radius, maxPoints); + } + + /** + * Return a new instance with the given center and radius in the X and Z + * axes with a Y that extends from the bottom of the extent to the top + * of the extent. + * + * @param extent the extent + * @param center the center position + * @param radius the radius in the X and Z axes + * @return a region + */ + public static CylinderRegion createRadius(Extent extent, BlockVector3 center, double radius) { + checkNotNull(extent); + checkNotNull(center); + Vector2 radiusVec = Vector2.at(radius, radius); + int minY = extent.getMinimumPoint().getBlockY(); + int maxY = extent.getMaximumPoint().getBlockY(); + return new CylinderRegion(center, radiusVec, minY, maxY); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java b/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java new file mode 100644 index 0000000..eb8afc1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java @@ -0,0 +1,236 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.storage.ChunkStore; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.HashSet; +import java.util.Set; + +/** + * Represents an ellipsoid region. + */ +public class EllipsoidRegion extends AbstractRegion { + + /** + * Stores the center. + */ + private BlockVector3 center; + + /** + * Stores the radii plus 0.5 on each axis. + */ + private Vector3 radius; + + /** + * Construct a new instance of this ellipsoid region. + * + * @param pos1 the first position + * @param pos2 the second position + */ + public EllipsoidRegion(BlockVector3 pos1, Vector3 pos2) { + this(null, pos1, pos2); + } + + /** + * Construct a new instance of this ellipsoid region. + * + * @param world the world + * @param center the center + * @param radius the radius + */ + public EllipsoidRegion(World world, BlockVector3 center, Vector3 radius) { + super(world); + this.center = center; + setRadius(radius); + } + + public EllipsoidRegion(EllipsoidRegion ellipsoidRegion) { + this(ellipsoidRegion.world, ellipsoidRegion.center, ellipsoidRegion.getRadius()); + } + + @Override + public BlockVector3 getMinimumPoint() { + return center.toVector3().subtract(getRadius()).toBlockPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return center.toVector3().add(getRadius()).toBlockPoint(); + } + + private static final BigDecimal ELLIPSOID_BASE_MULTIPLIER = BigDecimal.valueOf((4.0 / 3.0) * Math.PI); + + @Override + public long getVolume() { + return ELLIPSOID_BASE_MULTIPLIER + .multiply(BigDecimal.valueOf(radius.getX())) + .multiply(BigDecimal.valueOf(radius.getY())) + .multiply(BigDecimal.valueOf(radius.getZ())) + .setScale(0, RoundingMode.FLOOR) + .longValue(); + } + + @Override + public int getWidth() { + return (int) (2 * radius.getX()); + } + + @Override + public int getHeight() { + return (int) (2 * radius.getY()); + } + + @Override + public int getLength() { + return (int) (2 * radius.getZ()); + } + + private BlockVector3 calculateDiff(BlockVector3... changes) throws RegionOperationException { + BlockVector3 diff = BlockVector3.ZERO.add(changes); + + if ((diff.getBlockX() & 1) + (diff.getBlockY() & 1) + (diff.getBlockZ() & 1) != 0) { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.ellipsoid.error.even-horizontal")); + } + + return diff.divide(2).floor(); + } + + private Vector3 calculateChanges(BlockVector3... changes) { + Vector3 total = Vector3.ZERO; + for (BlockVector3 change : changes) { + total = total.add(change.abs().toVector3()); + } + + return total.divide(2).floor(); + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + center = center.add(calculateDiff(changes)); + radius = radius.add(calculateChanges(changes)); + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + center = center.subtract(calculateDiff(changes)); + Vector3 newRadius = radius.subtract(calculateChanges(changes)); + radius = Vector3.at(1.5, 1.5, 1.5).getMaximum(newRadius); + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + center = center.add(change); + } + + /** + * Get the center. + * + * @return center + */ + @Override + public Vector3 getCenter() { + return center.toVector3(); + } + + /** + * Set the center. + * + * @param center the center + */ + public void setCenter(BlockVector3 center) { + this.center = center; + } + + /** + * Get the radii. + * + * @return radii + */ + public Vector3 getRadius() { + return radius.subtract(0.5, 0.5, 0.5); + } + + /** + * Set the radii. + * + * @param radius the radius + */ + public void setRadius(Vector3 radius) { + this.radius = radius.add(0.5, 0.5, 0.5); + } + + @Override + public Set getChunks() { + final Set chunks = new HashSet<>(); + + final BlockVector3 min = getMinimumPoint(); + final BlockVector3 max = getMaximumPoint(); + final int centerY = center.getBlockY(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { + if (!contains(BlockVector3.at(x, centerY, z))) { + continue; + } + + chunks.add(BlockVector2.at( + x >> ChunkStore.CHUNK_SHIFTS, + z >> ChunkStore.CHUNK_SHIFTS + )); + } + } + + return chunks; + } + + @Override + public boolean contains(BlockVector3 position) { + return position.subtract(center).toVector3().divide(radius).lengthSq() <= 1; + } + + /** + * Returns string representation in the format + * "(centerX, centerY, centerZ) - (radiusX, radiusY, radiusZ)". + * + * @return string + */ + @Override + public String toString() { + return center + " - " + getRadius(); + } + + public void extendRadius(Vector3 minRadius) { + setRadius(minRadius.getMaximum(getRadius())); + } + + @Override + public EllipsoidRegion clone() { + return (EllipsoidRegion) super.clone(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/FlatRegion.java b/src/main/java/com/sk89q/worldedit/regions/FlatRegion.java new file mode 100644 index 0000000..3f2b271 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/FlatRegion.java @@ -0,0 +1,46 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.math.BlockVector2; + +public interface FlatRegion extends Region { + + /** + * Gets the minimum Y value. + * + * @return the Y value + */ + int getMinimumY(); + + /** + * Gets the maximum Y value. + * + * @return the Y value + */ + int getMaximumY(); + + /** + * Get this region as an iterable flat region. + * + * @return a flat region iterable + */ + Iterable asFlatRegion(); +} diff --git a/src/main/java/com/sk89q/worldedit/regions/NullRegion.java b/src/main/java/com/sk89q/worldedit/regions/NullRegion.java new file mode 100644 index 0000000..0b2b405 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/NullRegion.java @@ -0,0 +1,141 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * A region that contains no points. + */ +public class NullRegion implements Region { + + private World world; + + @Override + public BlockVector3 getMinimumPoint() { + return BlockVector3.ZERO; + } + + @Override + public BlockVector3 getMaximumPoint() { + return BlockVector3.ZERO; + } + + @Override + public Vector3 getCenter() { + return Vector3.ZERO; + } + + @Override + public long getVolume() { + return 0; + } + + @Override + public int getWidth() { + return 0; + } + + @Override + public int getHeight() { + return 0; + } + + @Override + public int getLength() { + return 0; + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.null.error.immutable")); + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.null.error.immutable")); + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.null.error.immutable")); + } + + @Override + public boolean contains(BlockVector3 position) { + return false; + } + + @Override + public Set getChunks() { + return Collections.emptySet(); + } + + @Override + public Set getChunkCubes() { + return Collections.emptySet(); + } + + @Override + public World getWorld() { + return world; + } + + @Override + public void setWorld(World world) { + this.world = world; + } + + @Override + public NullRegion clone() { + return new NullRegion(); + } + + @Override + public List polygonize(int maxPoints) { + return Collections.emptyList(); + } + + @Override + public Iterator iterator() { + return new Iterator() { + @Override + public boolean hasNext() { + return false; + } + + @Override + public BlockVector3 next() { + throw new NoSuchElementException(); + } + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java b/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java new file mode 100644 index 0000000..b03de8d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java @@ -0,0 +1,450 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator; +import com.sk89q.worldedit.regions.iterator.FlatRegionIterator; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * Represents a 2D polygonal region. + */ +public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { + + private List points; + private BlockVector2 min; + private BlockVector2 max; + private int minY; + private int maxY; + private boolean hasY = false; + + /** + * Construct the region. + */ + public Polygonal2DRegion() { + this((World) null); + } + + /** + * Construct the region. + * + * @param world the world + */ + public Polygonal2DRegion(World world) { + this(world, Collections.emptyList(), 0, 0); + hasY = false; + } + + /** + * Construct the region. + * + * @param world the world + * @param points list of points + * @param minY minimum Y + * @param maxY maximum Y + */ + public Polygonal2DRegion(World world, List points, int minY, int maxY) { + super(world); + this.points = new ArrayList<>(points); + this.minY = minY; + this.maxY = maxY; + hasY = true; + recalculate(); + } + + /** + * Make a copy of another region. + * + * @param region the other region + */ + public Polygonal2DRegion(Polygonal2DRegion region) { + this(region.world, region.points, region.minY, region.maxY); + hasY = region.hasY; + } + + /** + * Get the list of points. + * + * @return a list of points + */ + public List getPoints() { + return Collections.unmodifiableList(points); + } + + /** + * Recalculate the bounding box of this polygonal region. This should be + * called after points have been changed. + */ + protected void recalculate() { + if (points.isEmpty()) { + min = BlockVector2.ZERO; + minY = 0; + max = BlockVector2.ZERO; + maxY = 0; + return; + } + + int minX = points.get(0).getBlockX(); + int minZ = points.get(0).getBlockZ(); + int maxX = points.get(0).getBlockX(); + int maxZ = points.get(0).getBlockZ(); + + for (BlockVector2 v : points) { + int x = v.getBlockX(); + int z = v.getBlockZ(); + if (x < minX) { + minX = x; + } + if (z < minZ) { + minZ = z; + } + if (x > maxX) { + maxX = x; + } + if (z > maxZ) { + maxZ = z; + } + } + + int oldMinY = minY; + int oldMaxY = maxY; + minY = Math.min(oldMinY, oldMaxY); + maxY = Math.max(oldMinY, oldMaxY); + + minY = Math.min(Math.max(getWorldMinY(), minY), getWorldMaxY()); + maxY = Math.min(Math.max(getWorldMinY(), maxY), getWorldMaxY()); + + min = BlockVector2.at(minX, minZ); + max = BlockVector2.at(maxX, maxZ); + } + + /** + * Add a point to the list. + * + * @param position the position + */ + public void addPoint(BlockVector2 position) { + points.add(position); + recalculate(); + } + + /** + * Add a point to the list. + * + * @param position the position + */ + public void addPoint(BlockVector3 position) { + points.add(BlockVector2.at(position.getBlockX(), position.getBlockZ())); + recalculate(); + } + + @Override + public int getMinimumY() { + return minY; + } + + /** + * Set the minimum Y. + * + * @param y the Y + */ + public void setMinimumY(int y) { + hasY = true; + minY = y; + recalculate(); + } + + @Override + public int getMaximumY() { + return maxY; + } + + /** + * Set the maximum Y. + * + * @param y the Y + */ + public void setMaximumY(int y) { + hasY = true; + maxY = y; + recalculate(); + } + + @Override + public BlockVector3 getMinimumPoint() { + return min.toBlockVector3(minY); + } + + @Override + public BlockVector3 getMaximumPoint() { + return max.toBlockVector3(maxY); + } + + @Override + public long getVolume() { + long area = 0; + int i; + int j = points.size() - 1; + + for (i = 0; i < points.size(); ++i) { + long x = points.get(j).getBlockX() + points.get(i).getBlockX(); + long z = points.get(j).getBlockZ() - points.get(i).getBlockZ(); + area += x * z; + j = i; + } + + return BigDecimal.valueOf(area) + .multiply(BigDecimal.valueOf(0.5)) + .abs() + .setScale(0, RoundingMode.FLOOR) + .longValue() * (maxY - minY + 1); + } + + @Override + public int getWidth() { + return max.getBlockX() - min.getBlockX() + 1; + } + + @Override + public int getHeight() { + return maxY - minY + 1; + } + + @Override + public int getLength() { + return max.getBlockZ() - min.getBlockZ() + 1; + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + for (BlockVector3 change : changes) { + if (change.getBlockX() != 0 || change.getBlockZ() != 0) { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.polygon2d.error.expand-only-vertical")); + } + int changeY = change.getBlockY(); + if (changeY > 0) { + maxY += changeY; + } else { + minY += changeY; + } + } + recalculate(); + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + for (BlockVector3 change : changes) { + if (change.getBlockX() != 0 || change.getBlockZ() != 0) { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.polygon2d.error.contract-only-vertical")); + } + int changeY = change.getBlockY(); + if (changeY > 0) { + minY += changeY; + } else { + maxY += changeY; + } + } + recalculate(); + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + final double changeX = change.getX(); + final double changeY = change.getY(); + final double changeZ = change.getZ(); + + for (int i = 0; i < points.size(); ++i) { + BlockVector2 point = points.get(i); + points.set(i, BlockVector2.at(point.getX() + changeX, point.getZ() + changeZ)); + } + + minY += changeY; + maxY += changeY; + + recalculate(); + } + + @Override + public boolean contains(BlockVector3 position) { + return contains(points, minY, maxY, position); + } + + /** + * Checks to see if a point is inside a region. + * + * @param points a list of points + * @param minY the min Y + * @param maxY the max Y + * @param pt the position to check + * @return true if the given polygon contains the given point + */ + public static boolean contains(List points, int minY, int maxY, BlockVector3 pt) { + if (points.size() < 3) { + return false; + } + int targetX = pt.getBlockX(); //wide + int targetY = pt.getBlockY(); //height + int targetZ = pt.getBlockZ(); //depth + + if (targetY < minY || targetY > maxY) { + return false; + } + + boolean inside = false; + int npoints = points.size(); + int xNew; + int zNew; + int x1; + int z1; + int x2; + int z2; + long crossproduct; + int i; + + int xOld = points.get(npoints - 1).getBlockX(); + int zOld = points.get(npoints - 1).getBlockZ(); + + for (i = 0; i < npoints; ++i) { + xNew = points.get(i).getBlockX(); + zNew = points.get(i).getBlockZ(); + //Check for corner + if (xNew == targetX && zNew == targetZ) { + return true; + } + if (xNew > xOld) { + x1 = xOld; + x2 = xNew; + z1 = zOld; + z2 = zNew; + } else { + x1 = xNew; + x2 = xOld; + z1 = zNew; + z2 = zOld; + } + if (x1 <= targetX && targetX <= x2) { + crossproduct = ((long) targetZ - (long) z1) * (long) (x2 - x1) + - ((long) z2 - (long) z1) * (long) (targetX - x1); + if (crossproduct == 0) { + if ((z1 <= targetZ) == (targetZ <= z2)) { + return true; //on edge + } + } else if (crossproduct < 0 && (x1 != targetX)) { + inside = !inside; + } + } + xOld = xNew; + zOld = zNew; + } + + return inside; + } + + /** + * Return the number of points. + * + * @return the number of points + */ + public int size() { + return points.size(); + } + + /** + * Expand the height of the polygon to fit the specified Y. + * + * @param y the amount to expand + * @return true if the area was expanded + */ + public boolean expandY(int y) { + if (!hasY) { + minY = y; + maxY = y; + hasY = true; + return true; + } else if (y < minY) { + minY = y; + return true; + } else if (y > maxY) { + maxY = y; + return true; + } + + return false; + } + + @Override + public Iterator iterator() { + return new FlatRegion3DIterator(this); + } + + @Override + public Iterable asFlatRegion() { + return () -> new FlatRegionIterator(Polygonal2DRegion.this); + } + + /** + * Returns string representation in the format + * "(x1, z1) - ... - (xN, zN) * (minY - maxY)" + * + * @return string + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + List pts = getPoints(); + Iterator it = pts.iterator(); + while (it.hasNext()) { + BlockVector2 current = it.next(); + sb.append("(").append(current.getBlockX()).append(", ").append(current.getBlockZ()).append(")"); + if (it.hasNext()) { + sb.append(" - "); + } + } + sb.append(" * (").append(minY).append(" - ").append(maxY).append(")"); + return sb.toString(); + } + + @Override + public Polygonal2DRegion clone() { + Polygonal2DRegion clone = (Polygonal2DRegion) super.clone(); + clone.points = new ArrayList<>(points); + return clone; + } + + @Override + public List polygonize(int maxPoints) { + if (maxPoints >= 0 && maxPoints < points.size()) { + throw new IllegalArgumentException("Cannot polygonize a this Polygonal2DRegion into the amount of points given."); + } + + return points; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/Region.java b/src/main/java/com/sk89q/worldedit/regions/Region.java new file mode 100644 index 0000000..211e2a3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -0,0 +1,193 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.world.World; + +import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; + +/** + * Represents a physical shape. + */ +public interface Region extends Iterable, Cloneable { + + /** + * Get the lower point of a region. + * + * @return min. point + */ + BlockVector3 getMinimumPoint(); + + /** + * Get the upper point of a region. + * + * @return max. point + */ + BlockVector3 getMaximumPoint(); + + /** + * Get the bounding box of this region as a {@link CuboidRegion}. + * + * @return the bounding box + */ + default CuboidRegion getBoundingBox() { + return new CuboidRegion(getMinimumPoint(), getMaximumPoint()); + } + + /** + * Get the center point of a region. + * Note: Coordinates will not be integers + * if the corresponding lengths are even. + * + * @return center point + */ + Vector3 getCenter(); + + /** + * Get the number of blocks in the region. + * + * @return number of blocks + * @deprecated use {@link Region#getVolume()} to prevent overflows + */ + @Deprecated + default int getArea() { + return (int) getVolume(); + } + + /** + * Get the number of blocks in the region. + * + * @return number of blocks + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "getArea", + delegateParams = {} + ) + default long getVolume() { + DeprecationUtil.checkDelegatingOverride(getClass()); + + return getArea(); + } + + /** + * Get X-size. + * + * @return width + */ + int getWidth(); + + /** + * Get Y-size. + * + * @return height + */ + int getHeight(); + + /** + * Get Z-size. + * + * @return length + */ + int getLength(); + + /** + * Expand the region. + * + * @param changes array/arguments with multiple related changes + * @throws RegionOperationException if the operation cannot be performed + */ + void expand(BlockVector3... changes) throws RegionOperationException; + + /** + * Contract the region. + * + * @param changes array/arguments with multiple related changes + * @throws RegionOperationException if the operation cannot be performed + */ + void contract(BlockVector3... changes) throws RegionOperationException; + + /** + * Shift the region. + * + * @param change the change + * @throws RegionOperationException if the operation cannot be performed + */ + void shift(BlockVector3 change) throws RegionOperationException; + + /** + * Returns true based on whether the region contains the point. + * + * @param position the position + * @return true if contained + */ + boolean contains(BlockVector3 position); + + /** + * Get a list of chunks. + * + * @return a list of chunk coordinates + */ + Set getChunks(); + + /** + * Return a list of 16*16*16 chunks in a region. + * + * @return the chunk cubes this region overlaps with + */ + Set getChunkCubes(); + + /** + * Sets the world that the selection is in. + * + * @return the world, or null + */ + @Nullable World getWorld(); + + /** + * Sets the world that the selection is in. + * + * @param world the world, which may be null + */ + void setWorld(@Nullable World world); + + /** + * Make a clone of the region. + * + * @return a cloned version + */ + Region clone(); + + /** + * Polygonizes a cross-section or a 2D projection of the region orthogonal to the Y axis. + * + * @param maxPoints maximum number of points to generate. -1 for no limit. + * @return the points. + */ + List polygonize(int maxPoints); +} diff --git a/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java b/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java new file mode 100644 index 0000000..9d83ccd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java @@ -0,0 +1,140 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.google.common.collect.Iterators; +import com.sk89q.worldedit.math.BlockVector3; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An intersection of several other regions. Any location that is contained in one + * of the child regions is considered as contained by this region. + * + *

{@link #iterator()} returns a special iterator that will iterate through + * the iterators of each region in an undefined sequence. Some positions may + * be repeated if the position is contained in more than one region, but this cannot + * be guaranteed to occur.

+ */ +public class RegionIntersection extends AbstractRegion { + + private final List regions = new ArrayList<>(); + + /** + * Create a new instance with the included list of regions. + * + * @param regions a list of regions, which is copied + */ + public RegionIntersection(List regions) { + this(null, regions); + } + + /** + * Create a new instance with the included list of regions. + * + * @param regions a list of regions, which is copied + */ + public RegionIntersection(Region... regions) { + this(null, regions); + } + + /** + * Create a new instance with the included list of regions. + * + * @param world the world + * @param regions a list of regions, which is copied + */ + public RegionIntersection(World world, List regions) { + super(world); + checkNotNull(regions); + checkArgument(!regions.isEmpty(), "empty region list is not supported"); + this.regions.addAll(regions); + } + + /** + * Create a new instance with the included list of regions. + * + * @param world the world + * @param regions an array of regions, which is copied + */ + public RegionIntersection(World world, Region... regions) { + super(world); + checkNotNull(regions); + checkArgument(regions.length > 0, "empty region list is not supported"); + Collections.addAll(this.regions, regions); + } + + @Override + public BlockVector3 getMinimumPoint() { + BlockVector3 minimum = regions.get(0).getMinimumPoint(); + for (int i = 1; i < regions.size(); i++) { + minimum = regions.get(i).getMinimumPoint().getMinimum(minimum); + } + return minimum; + } + + @Override + public BlockVector3 getMaximumPoint() { + BlockVector3 maximum = regions.get(0).getMaximumPoint(); + for (int i = 1; i < regions.size(); i++) { + maximum = regions.get(i).getMaximumPoint().getMaximum(maximum); + } + return maximum; + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + checkNotNull(changes); + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.intersection.error.cannot-expand")); + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + checkNotNull(changes); + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.intersection.error.cannot-contract")); + } + + @Override + public boolean contains(BlockVector3 position) { + checkNotNull(position); + + for (Region region : regions) { + if (region.contains(position)) { + return true; + } + } + + return false; + } + + @Override + public Iterator iterator() { + return Iterators.concat(Iterators.transform(regions.iterator(), r -> r.iterator())); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/RegionOperationException.java b/src/main/java/com/sk89q/worldedit/regions/RegionOperationException.java new file mode 100644 index 0000000..632bc70 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/RegionOperationException.java @@ -0,0 +1,36 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.Component; + +public class RegionOperationException extends WorldEditException { + + @Deprecated + public RegionOperationException(String msg) { + super(msg); + } + + public RegionOperationException(Component msg) { + super(msg); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/RegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/RegionSelector.java new file mode 100644 index 0000000..0a821e7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/RegionSelector.java @@ -0,0 +1,199 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.google.common.collect.Lists; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Region selectors create {@link Region}s from a series of "selected points." + * They are used, for example, to allow users to create a {@link CuboidRegion} + * by selecting two corners of the cuboid. + */ +public interface RegionSelector { + + /** + * Get the world for the region selector. + * + * @return a world, which may be null + */ + @Nullable + World getWorld(); + + /** + * Set the world for the region selector. + * + * @param world the world, which may be null + */ + void setWorld(@Nullable World world); + + /** + * Called when the first point is selected. + * + * @param position the position + * @return true if something changed + */ + boolean selectPrimary(BlockVector3 position, SelectorLimits limits); + + /** + * Called when the second point is selected. + * + * @param position the position + * @return true if something changed + */ + boolean selectSecondary(BlockVector3 position, SelectorLimits limits); + + /** + * Tell the player information about his/her primary selection. + * + * @param actor the actor + * @param session the session + * @param position position + */ + void explainPrimarySelection(Actor actor, LocalSession session, BlockVector3 position); + + /** + * Tell the player information about his/her secondary selection. + * + * @param actor the actor + * @param session the session + * @param position position + */ + void explainSecondarySelection(Actor actor, LocalSession session, BlockVector3 position); + + /** + * Tell the player information about the region's changes. This may resend + * all the defining region information if needed. + * + * @param actor the actor + * @param session the session + */ + void explainRegionAdjust(Actor actor, LocalSession session); + + /** + * Get the primary position. + * + * @return the primary position + * @throws IncompleteRegionException thrown if a region has not been fully defined + */ + BlockVector3 getPrimaryPosition() throws IncompleteRegionException; + + /** + * Get the selection. + * + * @return the created region + * @throws IncompleteRegionException thrown if a region has not been fully defined + */ + Region getRegion() throws IncompleteRegionException; + + /** + * Get the region even if it's not fully defined. + * + * @return an incomplete region object that is incomplete + */ + Region getIncompleteRegion(); + + /** + * Returns whether the region has been fully defined. + * + * @return true if a selection is available + */ + boolean isDefined(); + + /** + * Get the number of blocks inside the region. + * + * @return number of blocks, or -1 if undefined + * @deprecated use {@link RegionSelector#getVolume()} + */ + @Deprecated + default int getArea() { + return (int) getVolume(); + } + + /** + * Get the number of blocks inside the region. + * + * @return number of blocks, or -1 if undefined + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "getArea", + delegateParams = {} + ) + default long getVolume() { + DeprecationUtil.checkDelegatingOverride(getClass()); + + return getArea(); + } + + /** + * Update the selector with changes to the region. + */ + void learnChanges(); + + /** + * Clear the selection. + */ + void clear(); + + /** + * Get a lowercase name of this region selector type. + * + * @return a lower case name of the type + */ + String getTypeName(); + + /** + * Get lines of information about the selection. + * + * @return a list of lines describing the region + */ + @Deprecated + default List getInformationLines() { + return Lists.newArrayList(); + } + + /** + * Get lines of information about the selection. + * + * @return a list of lines describing the region. + */ + default List getSelectionInfoLines() { + return getInformationLines().stream() + .map(line -> TextComponent.of(line, TextColor.LIGHT_PURPLE)) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/regions/Regions.java b/src/main/java/com/sk89q/worldedit/regions/Regions.java new file mode 100644 index 0000000..040ec28 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/Regions.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +/** + * Utility methods relating to {@link Region}s. + */ +public final class Regions { + + private Regions() { + } + + /** + * Get the minimum Y coordinate of the given region using the region's + * {@link Region#getMinimumPoint()} method. + * + * @param region the region + * @return the Y coordinate + */ + public static double minimumY(Region region) { + return region.getMinimumPoint().getY(); + } + + /** + * Get the maximum Y coordinate of the given region using the region's + * {@link Region#getMaximumPoint()} method. + * + * @param region the region + * @return the Y coordinate + */ + public static double maximumY(Region region) { + return region.getMaximumPoint().getY(); + } + + /** + * Get the minimum Y coordinate of the given region using the region's + * {@link Region#getMinimumPoint()} method. + * + * @param region the region + * @return the Y coordinate + */ + public static int minimumBlockY(Region region) { + return region.getMinimumPoint().getBlockY(); + } + + /** + * Get the maximum Y coordinate of the given region using the region's + * {@link Region#getMaximumPoint()} method. + * + * @param region the region + * @return the Y coordinate + */ + public static int maximumBlockY(Region region) { + return region.getMaximumPoint().getBlockY(); + } + + /** + * Attempt to get a {@link FlatRegion} from the given region. + * + *

If the given region is already a {@link FlatRegion}, then the region + * will be cast and returned. Otherwise, a new {@link CuboidRegion} will + * be created covers the provided region's minimum and maximum extents.

+ * + * @param region the region + * @return a flat region + */ + public static FlatRegion asFlatRegion(Region region) { + if (region instanceof FlatRegion) { + return (FlatRegion) region; + } else { + return CuboidRegion.makeCuboid(region); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java b/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java new file mode 100644 index 0000000..2f74adb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java @@ -0,0 +1,191 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.Identity; +import com.sk89q.worldedit.math.transform.Transform; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Transforms another region according to a provided vector {@code Transform}. + * + * @see Transform + */ +public class TransformRegion extends AbstractRegion { + + private final Region region; + private Transform transform = new Identity(); + + /** + * Create a new instance. + * + * @param region the region + * @param transform the transform + */ + public TransformRegion(Region region, Transform transform) { + this(null, region, transform); + } + + /** + * Create a new instance. + * + * @param world the world, which may be null + * @param region the region + * @param transform the transform + */ + public TransformRegion(@Nullable World world, Region region, Transform transform) { + super(world); + checkNotNull(region); + checkNotNull(transform); + this.region = region; + this.transform = transform; + } + + /** + * Get the untransformed, base region. + * + * @return the base region + */ + public Region getRegion() { + return region; + } + + /** + * Get the transform that is applied. + * + * @return the transform + */ + public Transform getTransform() { + return transform; + } + + /** + * Set the transform that is applied. + * + * @param transform the transform + */ + public void setTransform(Transform transform) { + checkNotNull(transform); + this.transform = transform; + } + + @Override + public BlockVector3 getMinimumPoint() { + return transform.apply(region.getMinimumPoint().toVector3()).toBlockPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return transform.apply(region.getMaximumPoint().toVector3()).toBlockPoint(); + } + + @Override + public Vector3 getCenter() { + return transform.apply(region.getCenter()); + } + + @Override + public long getVolume() { + return region.getVolume(); // Cannot transform this + } + + @Override + public int getWidth() { + return getMaximumPoint().subtract(getMinimumPoint()).getBlockX() + 1; + } + + @Override + public int getHeight() { + return getMaximumPoint().subtract(getMinimumPoint()).getBlockY() + 1; + } + + @Override + public int getLength() { + return getMaximumPoint().subtract(getMinimumPoint()).getBlockZ() + 1; + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.transform.error.cannot-expand")); + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.transform.error.cannot-contract")); + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.transform.error.cannot-change")); + } + + @Override + public boolean contains(BlockVector3 position) { + return region.contains(transform.inverse().apply(position.toVector3()).toBlockPoint()); + } + + @Override + public List polygonize(int maxPoints) { + List origPoints = region.polygonize(maxPoints); + List transformedPoints = new ArrayList<>(); + for (BlockVector2 vector : origPoints) { + transformedPoints.add(transform.apply(vector.toVector3(0)).toVector2().toBlockPoint()); + } + return transformedPoints; + } + + @Override + public Iterator iterator() { + final Iterator it = region.iterator(); + + return new Iterator() { + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public BlockVector3 next() { + BlockVector3 next = it.next(); + if (next != null) { + return transform.apply(next.toVector3()).toBlockPoint(); + } else { + return null; + } + } + + @Override + public void remove() { + it.remove(); + } + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/regions/factory/CuboidRegionFactory.java b/src/main/java/com/sk89q/worldedit/regions/factory/CuboidRegionFactory.java new file mode 100644 index 0000000..6021d53 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/factory/CuboidRegionFactory.java @@ -0,0 +1,33 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.factory; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; + +public class CuboidRegionFactory implements RegionFactory { + + @Override + public Region createCenteredAt(BlockVector3 position, double size) { + return CuboidRegion.fromCenter(position, (int) size); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/factory/CylinderRegionFactory.java b/src/main/java/com/sk89q/worldedit/regions/factory/CylinderRegionFactory.java new file mode 100644 index 0000000..7203ff3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/factory/CylinderRegionFactory.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.factory; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.regions.CylinderRegion; +import com.sk89q.worldedit.regions.Region; + +public class CylinderRegionFactory implements RegionFactory { + + private final double height; + + public CylinderRegionFactory(double height) { + this.height = height; + } + + @Override + public Region createCenteredAt(BlockVector3 position, double size) { + return new CylinderRegion(position, Vector2.at(size, size), position.getBlockY() - (int) (height / 2), position.getBlockY() + (int) (height / 2)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/factory/RegionFactory.java b/src/main/java/com/sk89q/worldedit/regions/factory/RegionFactory.java new file mode 100644 index 0000000..5c80d53 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/factory/RegionFactory.java @@ -0,0 +1,29 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.factory; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; + +public interface RegionFactory { + + Region createCenteredAt(BlockVector3 position, double size); + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/factory/SphereRegionFactory.java b/src/main/java/com/sk89q/worldedit/regions/factory/SphereRegionFactory.java new file mode 100644 index 0000000..7a26b22 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/factory/SphereRegionFactory.java @@ -0,0 +1,34 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.factory; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.EllipsoidRegion; +import com.sk89q.worldedit.regions.Region; + +public class SphereRegionFactory implements RegionFactory { + + @Override + public Region createCenteredAt(BlockVector3 position, double size) { + return new EllipsoidRegion(position, Vector3.at(size, size, size)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java b/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java new file mode 100644 index 0000000..e7ae993 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java @@ -0,0 +1,89 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.iterator; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.FlatRegion; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class FlatRegion3DIterator implements Iterator { + + private final Iterator flatIterator; + private final int minY; + private final int maxY; + + private BlockVector2 next2D; + private int nextY; + + public FlatRegion3DIterator(FlatRegion region, Iterator flatIterator) { + checkNotNull(region); + checkNotNull(flatIterator); + + this.flatIterator = flatIterator; + this.minY = region.getMinimumY(); + this.maxY = region.getMaximumY(); + + if (flatIterator.hasNext()) { + this.next2D = flatIterator.next(); + } else { + this.next2D = null; + } + this.nextY = minY; + } + + public FlatRegion3DIterator(FlatRegion region) { + this(region, region.asFlatRegion().iterator()); + } + + @Override + public boolean hasNext() { + return next2D != null; + } + + @Override + public BlockVector3 next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + BlockVector3 current = BlockVector3.at(next2D.getBlockX(), nextY, next2D.getBlockZ()); + if (nextY < maxY) { + nextY++; + } else if (flatIterator.hasNext()) { + next2D = flatIterator.next(); + nextY = minY; + } else { + next2D = null; + } + + return current; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java b/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java new file mode 100644 index 0000000..4aea7d0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java @@ -0,0 +1,99 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.iterator; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class FlatRegionIterator implements Iterator { + + private final Region region; + private final int y; + private final int minX; + private final int maxX; + private final int maxZ; + private int nextX; + private int nextZ; + + public FlatRegionIterator(Region region) { + checkNotNull(region); + + this.region = region; + + BlockVector3 min = region.getMinimumPoint(); + BlockVector3 max = region.getMaximumPoint(); + + this.y = min.getBlockY(); + + this.minX = min.getBlockX(); + + this.nextX = minX; + this.nextZ = min.getBlockZ(); + + this.maxX = max.getBlockX(); + this.maxZ = max.getBlockZ(); + + forward(); + } + + @Override + public boolean hasNext() { + return nextX != Integer.MIN_VALUE; + } + + private void forward() { + while (hasNext() && !region.contains(BlockVector3.at(nextX, y, nextZ))) { + forwardOne(); + } + } + + @Override + public BlockVector2 next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + BlockVector2 answer = BlockVector2.at(nextX, nextZ); + + forwardOne(); + forward(); + + return answer; + } + + private void forwardOne() { + if (++nextX <= maxX) { + return; + } + nextX = minX; + + if (++nextZ <= maxZ) { + return; + } + nextX = Integer.MIN_VALUE; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java b/src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java new file mode 100644 index 0000000..9e2c9b8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java @@ -0,0 +1,105 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.iterator; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; + +import java.util.Iterator; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class RegionIterator implements Iterator { + + private final Region region; + private final int maxX; + private final int maxY; + private final int maxZ; + private final BlockVector3 min; + private int nextX; + private int nextY; + private int nextZ; + + public RegionIterator(Region region) { + checkNotNull(region); + + this.region = region; + + BlockVector3 max = region.getMaximumPoint(); + this.maxX = max.getBlockX(); + this.maxY = max.getBlockY(); + this.maxZ = max.getBlockZ(); + + this.min = region.getMinimumPoint(); + this.nextX = min.getBlockX(); + this.nextY = min.getBlockY(); + this.nextZ = min.getBlockZ(); + + forward(); + } + + @Override + public boolean hasNext() { + return nextX != Integer.MIN_VALUE; + } + + private void forward() { + while (hasNext() && !region.contains(BlockVector3.at(nextX, nextY, nextZ))) { + forwardOne(); + } + } + + @Override + public BlockVector3 next() { + if (!hasNext()) { + throw new java.util.NoSuchElementException(); + } + + BlockVector3 answer = BlockVector3.at(nextX, nextY, nextZ); + + forwardOne(); + forward(); + + return answer; + } + + private void forwardOne() { + if (++nextX <= maxX) { + return; + } + nextX = min.getBlockX(); + + if (++nextY <= maxY) { + return; + } + nextY = min.getBlockY(); + + if (++nextZ <= maxZ) { + return; + } + nextX = Integer.MIN_VALUE; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/polyhedron/Edge.java b/src/main/java/com/sk89q/worldedit/regions/polyhedron/Edge.java new file mode 100644 index 0000000..1400119 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/polyhedron/Edge.java @@ -0,0 +1,86 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.polyhedron; + +import com.sk89q.worldedit.math.Vector3; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class Edge { + + private final Vector3 start; + private final Vector3 end; + + public Edge(Vector3 start, Vector3 end) { + checkNotNull(start); + checkNotNull(end); + + this.start = start; + this.end = end; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Edge)) { + return false; + } + + Edge otherEdge = (Edge) other; + if (this.start.equals(otherEdge.end) && this.end.equals(otherEdge.start)) { + return true; + } + + return this.end.equals(otherEdge.end) && this.start.equals(otherEdge.start); + } + + @Override + public int hashCode() { + return start.hashCode() ^ end.hashCode(); + } + + + @Override + public String toString() { + return "(" + this.start + "," + this.end + ")"; + } + + /** + * Create a triangle from { this.start, this.end, vertex } + * + * @param vertex the 3rd vertex for the triangle + * @return a triangle + */ + public Triangle createTriangle(Vector3 vertex) { + checkNotNull(vertex); + return new Triangle(this.start, this.end, vertex); + } + + /** + * Create a triangle from { this.start, vertex, this.end }. + * + * @param vertex the second vertex + * @return a new triangle + */ + public Triangle createTriangle2(Vector3 vertex) { + checkNotNull(vertex); + return new Triangle(this.start, vertex, this.end); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/polyhedron/Triangle.java b/src/main/java/com/sk89q/worldedit/regions/polyhedron/Triangle.java new file mode 100644 index 0000000..400fabb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/polyhedron/Triangle.java @@ -0,0 +1,113 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.polyhedron; + +import com.sk89q.worldedit.math.Vector3; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class Triangle { + + private String tag = "Triangle"; + private final Vector3[] vertices; + private final Vector3 normal; + private final double maxDotProduct; + + /** + * Constructs a triangle with the given vertices (counter-clockwise). + * + * @param v0 first vertex + * @param v1 second vertex + * @param v2 third vertex + */ + public Triangle(Vector3 v0, Vector3 v1, Vector3 v2) { + checkNotNull(v0); + checkNotNull(v1); + checkNotNull(v2); + + vertices = new Vector3[] { v0, v1, v2 }; + + this.normal = v1.subtract(v0).cross(v2.subtract(v0)).normalize(); + this.maxDotProduct = Math.max(Math.max(normal.dot(v0), normal.dot(v1)), normal.dot(v2)); + } + + /** + * Returns the triangle's vertex with the given index, counter-clockwise. + * + * @param index Vertex index. Valid input: 0..2 + * @return a vertex + */ + public Vector3 getVertex(int index) { + return vertices[index]; + } + + /** + * Returns the triangle's edge with the given index, counter-clockwise. + * + * @param index Edge index. Valid input: 0..2 + * @return an edge + */ + public Edge getEdge(int index) { + if (index == vertices.length - 1) { + return new Edge(vertices[index], vertices[0]); + } + return new Edge(vertices[index], vertices[index + 1]); + } + + /** + * Returns whether the given point is above the plane the triangle is in. + * + * @param pt the point to test + * @return true if the point is below + */ + public boolean below(Vector3 pt) { + checkNotNull(pt); + return normal.dot(pt) < maxDotProduct; + } + + /** + * Returns whether the given point is above the plane the triangle is in. + * + * @param pt the point to test + * @return true if the point is above + */ + public boolean above(Vector3 pt) { + checkNotNull(pt); + return normal.dot(pt) > maxDotProduct; + } + + /** + * Set the triangle's tag. + * + * @param tag the tag + * @return this object + */ + public Triangle tag(String tag) { + checkNotNull(tag); + this.tag = tag; + return this; + } + + @Override + public String toString() { + return tag + "(" + this.vertices[0] + "," + this.vertices[1] + "," + this.vertices[2] + ")"; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java new file mode 100644 index 0000000..2651d54 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java @@ -0,0 +1,274 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.internal.cui.SelectionPolygonEvent; +import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.ConvexPolyhedralRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.polyhedron.Triangle; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; +import java.util.*; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates a {@code ConvexPolyhedralRegion} from a user's selections. + */ +public class ConvexPolyhedralRegionSelector implements RegionSelector, CUIRegion { + + private final transient ConvexPolyhedralRegion region; + private transient BlockVector3 pos1; + + /** + * Create a new selector with a {@code null} world. + */ + public ConvexPolyhedralRegionSelector() { + this((World) null); + } + + /** + * Create a new selector. + * + * @param world the world, which may be {@code null} + */ + public ConvexPolyhedralRegionSelector(@Nullable World world) { + region = new ConvexPolyhedralRegion(world); + } + + /** + * Create a new selector. + * + * @param oldSelector the old selector + */ + public ConvexPolyhedralRegionSelector(RegionSelector oldSelector) { + checkNotNull(oldSelector); + + if (oldSelector instanceof ConvexPolyhedralRegionSelector) { + final ConvexPolyhedralRegionSelector convexPolyhedralRegionSelector = (ConvexPolyhedralRegionSelector) oldSelector; + + pos1 = convexPolyhedralRegionSelector.pos1; + region = new ConvexPolyhedralRegion(convexPolyhedralRegionSelector.region); + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + region = new ConvexPolyhedralRegion(oldSelector.getIncompleteRegion().getWorld()); + return; + } + + final int minY = oldRegion.getMinimumPoint().getBlockY(); + final int maxY = oldRegion.getMaximumPoint().getBlockY(); + + region = new ConvexPolyhedralRegion(oldRegion.getWorld()); + + for (final BlockVector2 pt : new ArrayList<>(oldRegion.polygonize(Integer.MAX_VALUE))) { + region.addVertex(pt.toBlockVector3(minY)); + region.addVertex(pt.toBlockVector3(maxY)); + } + + learnChanges(); + } + } + + @Nullable + @Override + public World getWorld() { + return region.getWorld(); + } + + @Override + public void setWorld(@Nullable World world) { + region.setWorld(world); + } + + @Override + public boolean selectPrimary(BlockVector3 position, SelectorLimits limits) { + checkNotNull(position); + clear(); + pos1 = position; + return region.addVertex(position); + } + + @Override + public boolean selectSecondary(BlockVector3 position, SelectorLimits limits) { + checkNotNull(position); + + Optional vertexLimit = limits.getPolyhedronVertexLimit(); + + if (vertexLimit.isPresent() && region.getVertices().size() > vertexLimit.get()) { + return false; + } + + return region.addVertex(position); + } + + @Override + public BlockVector3 getPrimaryPosition() throws IncompleteRegionException { + return pos1; + } + + @Override + public Region getRegion() throws IncompleteRegionException { + if (!region.isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + @Override + public Region getIncompleteRegion() { + return region; + } + + @Override + public boolean isDefined() { + return region.isDefined(); + } + + @Override + public long getVolume() { + return region.getVolume(); + } + + @Override + public void learnChanges() { + pos1 = region.getVertices().iterator().next(); + } + + @Override + public void clear() { + region.clear(); + } + + @Override + public String getTypeName() { + return "Convex Polyhedron"; + } + + @Override + public List getSelectionInfoLines() { + List ret = new ArrayList<>(); + + ret.add(TranslatableComponent.of("worldedit.selection.convex.info.vertices", TextComponent.of(region.getVertices().size()))); + ret.add(TranslatableComponent.of("worldedit.selection.convex.info.triangles", TextComponent.of(region.getTriangles().size()))); + + return ret; + } + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, BlockVector3 pos) { + checkNotNull(player); + checkNotNull(session); + checkNotNull(pos); + + session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); + session.describeCUI(player); + + player.printInfo(TranslatableComponent.of("worldedit.selection.convex.explain.primary", TextComponent.of(pos.toString()))); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, BlockVector3 pos) { + checkNotNull(player); + checkNotNull(session); + checkNotNull(pos); + + session.describeCUI(player); + + player.printInfo(TranslatableComponent.of("worldedit.selection.convex.explain.secondary", TextComponent.of(pos.toString()))); + } + + @Override + public void explainRegionAdjust(Actor player, LocalSession session) { + checkNotNull(player); + checkNotNull(session); + + session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); + session.describeCUI(player); + } + + @Override + public int getProtocolVersion() { + return 3; + } + + @Override + public String getTypeID() { + return "polyhedron"; + } + + @Override + public void describeCUI(LocalSession session, Actor player) { + checkNotNull(player); + checkNotNull(session); + + Collection vertices = region.getVertices(); + Collection triangles = region.getTriangles(); + + Map vertexIds = new HashMap<>(vertices.size()); + int lastVertexId = -1; + for (BlockVector3 vertex : vertices) { + vertexIds.put(vertex, ++lastVertexId); + session.dispatchCUIEvent(player, new SelectionPointEvent(lastVertexId, vertex, getVolume())); + } + + for (Triangle triangle : triangles) { + final int[] v = new int[3]; + for (int i = 0; i < 3; ++i) { + v[i] = vertexIds.get(triangle.getVertex(i).toBlockPoint()); + } + session.dispatchCUIEvent(player, new SelectionPolygonEvent(v)); + } + } + + @Override + public String getLegacyTypeID() { + return "cuboid"; + } + + @Override + public void describeLegacyCUI(LocalSession session, Actor player) { + checkNotNull(player); + checkNotNull(session); + + if (isDefined()) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getVolume())); + session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getVolume())); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java new file mode 100644 index 0000000..11843dd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java @@ -0,0 +1,318 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import com.sk89q.worldedit.world.World; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates a {@code CuboidRegion} from a user's selections. + */ +public class CuboidRegionSelector implements RegionSelector, CUIRegion { + + protected transient BlockVector3 position1; + protected transient BlockVector3 position2; + protected transient CuboidRegion region; + + /** + * Create a new region selector with a {@code null} world. + */ + public CuboidRegionSelector() { + this((World) null); + } + + /** + * Create a new region selector. + * + * @param world the world, which may be {@code null} + */ + public CuboidRegionSelector(@Nullable World world) { + region = new CuboidRegion(world, BlockVector3.ZERO, BlockVector3.ZERO); + } + + /** + * Create a copy of another selector. + * + * @param oldSelector another selector + */ + public CuboidRegionSelector(RegionSelector oldSelector) { + this(checkNotNull(oldSelector).getIncompleteRegion().getWorld()); + + if (oldSelector instanceof CuboidRegionSelector) { + final CuboidRegionSelector cuboidRegionSelector = (CuboidRegionSelector) oldSelector; + + position1 = cuboidRegionSelector.position1; + position2 = cuboidRegionSelector.position2; + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + position1 = oldRegion.getMinimumPoint(); + position2 = oldRegion.getMaximumPoint(); + } + + region.setPos1(position1); + region.setPos2(position2); + } + + /** + * Create a new region selector with the given two positions. + * + * @param world the world + * @param position1 position 1 + * @param position2 position 2 + */ + public CuboidRegionSelector(@Nullable World world, BlockVector3 position1, BlockVector3 position2) { + this(world); + checkNotNull(position1); + checkNotNull(position2); + this.position1 = position1; + this.position2 = position2; + region.setPos1(position1); + region.setPos2(position2); + } + + @Nullable + @Override + public World getWorld() { + return region.getWorld(); + } + + @Override + public void setWorld(@Nullable World world) { + region.setWorld(world); + } + + @Override + public boolean selectPrimary(BlockVector3 position, SelectorLimits limits) { + checkNotNull(position); + + if (position.equals(position1)) { + return false; + } + + position1 = position; + region.setPos1(position1); + return true; + } + + @Override + public boolean selectSecondary(BlockVector3 position, SelectorLimits limits) { + checkNotNull(position); + + if (position.equals(position2)) { + return false; + } + + position2 = position; + region.setPos2(position2); + return true; + } + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, BlockVector3 pos) { + checkNotNull(player); + checkNotNull(session); + checkNotNull(pos); + + if (position1 != null && position2 != null) { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.cuboid.explain.primary-area", + TextComponent.of(position1.toString()), + TextComponent.of(region.getVolume()) + )); + } else if (position1 != null) { + player.printInfo(TranslatableComponent.of("worldedit.selection.cuboid.explain.primary", TextComponent.of(position1.toString()))); + } + + session.dispatchCUIEvent(player, new SelectionPointEvent(0, pos, getVolume())); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, BlockVector3 pos) { + checkNotNull(player); + checkNotNull(session); + checkNotNull(pos); + + if (position1 != null && position2 != null) { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.cuboid.explain.secondary-area", + TextComponent.of(position2.toString()), + TextComponent.of(region.getVolume()) + )); + } else if (position2 != null) { + player.printInfo(TranslatableComponent.of("worldedit.selection.cuboid.explain.secondary", TextComponent.of(position2.toString()))); + } + + session.dispatchCUIEvent(player, new SelectionPointEvent(1, pos, getVolume())); + } + + @Override + public void explainRegionAdjust(Actor player, LocalSession session) { + checkNotNull(player); + checkNotNull(session); + + session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); + + if (position1 != null) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, position1, getVolume())); + } + + if (position2 != null) { + session.dispatchCUIEvent(player, new SelectionPointEvent(1, position2, getVolume())); + } + } + + @Override + public BlockVector3 getPrimaryPosition() throws IncompleteRegionException { + if (position1 == null) { + throw new IncompleteRegionException(); + } + + return position1; + } + + @Override + public boolean isDefined() { + return position1 != null && position2 != null; + } + + @Override + public CuboidRegion getRegion() throws IncompleteRegionException { + if (position1 == null || position2 == null) { + throw new IncompleteRegionException(); + } + + return region; + } + + @Override + public CuboidRegion getIncompleteRegion() { + return region; + } + + @Override + public void learnChanges() { + position1 = region.getPos1(); + position2 = region.getPos2(); + } + + @Override + public void clear() { + position1 = null; + position2 = null; + region.setPos1(BlockVector3.ZERO); + region.setPos2(BlockVector3.ZERO); + } + + @Override + public String getTypeName() { + return "cuboid"; + } + + @Override + public List getSelectionInfoLines() { + final List lines = new ArrayList<>(); + + if (position1 != null) { + lines.add(TranslatableComponent.of("worldedit.selection.cuboid.info.pos1", TextComponent.of(position1.toString()) + .clickEvent(ClickEvent.of(ClickEvent.Action.COPY_TO_CLIPBOARD, position1.toParserString())) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to copy"))))); + } + + if (position2 != null) { + lines.add(TranslatableComponent.of("worldedit.selection.cuboid.info.pos2", TextComponent.of(position2.toString()) + .clickEvent(ClickEvent.of(ClickEvent.Action.COPY_TO_CLIPBOARD, position2.toParserString())) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to copy"))))); + } + + return lines; + } + + @Override + public long getVolume() { + if (position1 == null) { + return -1; + } + + if (position2 == null) { + return -1; + } + + return region.getVolume(); + } + + @Override + public void describeCUI(LocalSession session, Actor player) { + if (position1 != null) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, position1, getVolume())); + } + + if (position2 != null) { + session.dispatchCUIEvent(player, new SelectionPointEvent(1, position2, getVolume())); + } + } + + @Override + public void describeLegacyCUI(LocalSession session, Actor player) { + describeCUI(session, player); + } + + @Override + public int getProtocolVersion() { + return 0; + } + + @Override + public String getTypeID() { + return "cuboid"; + } + + @Override + public String getLegacyTypeID() { + return "cuboid"; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java new file mode 100644 index 0000000..ea987d7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java @@ -0,0 +1,310 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionCylinderEvent; +import com.sk89q.worldedit.internal.cui.SelectionMinMaxEvent; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.CylinderRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import com.sk89q.worldedit.world.World; + +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates a {@code CylinderRegionSelector} from a user's selections. + */ +public class CylinderRegionSelector implements RegionSelector, CUIRegion { + + protected static final transient NumberFormat NUMBER_FORMAT; + protected transient CylinderRegion region; + protected transient boolean selectedCenter; + protected transient boolean selectedRadius; + + static { + NUMBER_FORMAT = (NumberFormat) NumberFormat.getInstance().clone(); + NUMBER_FORMAT.setMaximumFractionDigits(3); + } + + /** + * Create a new region selector with a {@code null} world. + */ + public CylinderRegionSelector() { + this((World) null); + } + + /** + * Create a new region selector. + * + * @param world the world, which may be {@code null} + */ + public CylinderRegionSelector(@Nullable World world) { + region = new CylinderRegion(world); + } + + /** + * Create a new selector from the given one. + * + * @param oldSelector the old selector + */ + public CylinderRegionSelector(RegionSelector oldSelector) { + this(checkNotNull(oldSelector).getIncompleteRegion().getWorld()); + + if (oldSelector instanceof CylinderRegionSelector) { + final CylinderRegionSelector cylSelector = (CylinderRegionSelector) oldSelector; + + region = new CylinderRegion(cylSelector.region); + selectedCenter = cylSelector.selectedCenter; + selectedRadius = cylSelector.selectedRadius; + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + BlockVector3 pos1 = oldRegion.getMinimumPoint(); + BlockVector3 pos2 = oldRegion.getMaximumPoint(); + + BlockVector3 center = pos1.add(pos2).divide(2).floor(); + region.setCenter(center.toBlockVector2()); + region.setRadius(pos2.toBlockVector2().subtract(center.toBlockVector2()).toVector2()); + + region.setMaximumY(Math.max(pos1.getBlockY(), pos2.getBlockY())); + region.setMinimumY(Math.min(pos1.getBlockY(), pos2.getBlockY())); + + selectedCenter = true; + selectedRadius = true; + } + } + + /** + * Create a new selector. + * + * @param world the world + * @param center the center + * @param radius the radius + * @param minY the minimum Y + * @param maxY the maximum Y + */ + public CylinderRegionSelector(@Nullable World world, BlockVector2 center, Vector2 radius, int minY, int maxY) { + this(world); + + region.setCenter(center); + region.setRadius(radius); + + region.setMinimumY(Math.min(minY, maxY)); + region.setMaximumY(Math.max(minY, maxY)); + + selectedCenter = true; + selectedRadius = true; + } + + @Nullable + @Override + public World getWorld() { + return region.getWorld(); + } + + @Override + public void setWorld(@Nullable World world) { + region.setWorld(world); + } + + @Override + public boolean selectPrimary(BlockVector3 position, SelectorLimits limits) { + if (selectedCenter && position.equals(region.getCenter().toBlockPoint()) && !selectedRadius) { + return false; + } + + region = new CylinderRegion(region.getWorld()); + region.setCenter(position.toBlockVector2()); + region.setY(position.getBlockY()); + + selectedCenter = true; + selectedRadius = false; + + return true; + } + + @Override + public boolean selectSecondary(BlockVector3 position, SelectorLimits limits) { + if (!selectedCenter) { + return true; + } + + final Vector2 diff = position.toVector3().subtract(region.getCenter()).toVector2(); + final Vector2 minRadius = diff.getMaximum(diff.multiply(-1.0)); + region.extendRadius(minRadius); + + region.setY(position.getBlockY()); + + selectedRadius = true; + + return true; + } + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, BlockVector3 pos) { + player.printInfo(TranslatableComponent.of("worldedit.selection.cylinder.explain.primary", TextComponent.of(pos.toString()))); + + session.describeCUI(player); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, BlockVector3 pos) { + if (selectedCenter) { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.cylinder.explain.secondary", + TextComponent.of(NUMBER_FORMAT.format(region.getRadius().getX())), + TextComponent.of(NUMBER_FORMAT.format(region.getRadius().getZ())), + TextComponent.of(region.getVolume()) + )); + } else { + player.printError(TranslatableComponent.of("worldedit.selection.cylinder.explain.secondary-missing")); + return; + } + + session.describeCUI(player); + } + + @Override + public void explainRegionAdjust(Actor player, LocalSession session) { + session.describeCUI(player); + } + + @Override + public BlockVector3 getPrimaryPosition() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region.getCenter().toBlockPoint(); + } + + @Override + public CylinderRegion getRegion() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + @Override + public CylinderRegion getIncompleteRegion() { + return region; + } + + @Override + public boolean isDefined() { + // selectedCenter is implied by selectedRadius + return selectedRadius; + } + + @Override + public void learnChanges() { + } + + @Override + public void clear() { + region = new CylinderRegion(region.getWorld()); + selectedCenter = false; + selectedRadius = false; + } + + @Override + public String getTypeName() { + return "Cylinder"; + } + + @Override + public List getSelectionInfoLines() { + final List lines = new ArrayList<>(); + + if (!region.getCenter().equals(Vector3.ZERO)) { + Vector3 center = region.getCenter(); + lines.add(TranslatableComponent.of("worldedit.selection.cylinder.info.center", TextComponent.of(center.toString()) + .clickEvent(ClickEvent.of(ClickEvent.Action.COPY_TO_CLIPBOARD, center.toParserString())) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to copy"))))); + } + if (!region.getRadius().equals(Vector2.ZERO)) { + lines.add(TranslatableComponent.of("worldedit.selection.cylinder.info.radius", TextComponent.of(region.getRadius().toString()))); + } + + return lines; + } + + @Override + public long getVolume() { + return region.getVolume(); + } + + @Override + public void describeCUI(LocalSession session, Actor player) { + session.dispatchCUIEvent(player, new SelectionCylinderEvent(region.getCenter().toBlockPoint(), region.getRadius())); + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + @Override + public void describeLegacyCUI(LocalSession session, Actor player) { + if (isDefined()) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getVolume())); + session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getVolume())); + } + } + + @Override + public int getProtocolVersion() { + return 1; + } + + @Override + public String getTypeID() { + return "cylinder"; + } + + @Override + public String getLegacyTypeID() { + return "cuboid"; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java new file mode 100644 index 0000000..ef3baf8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java @@ -0,0 +1,295 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionEllipsoidPointEvent; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.EllipsoidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import com.sk89q.worldedit.world.World; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates a {@code EllipsoidRegionSelector} from a user's selections. + */ +public class EllipsoidRegionSelector implements RegionSelector, CUIRegion { + + protected transient EllipsoidRegion region; + protected transient boolean started = false; + protected transient boolean selectedRadius = false; + + /** + * Create a new selector with a {@code null} world. + */ + public EllipsoidRegionSelector() { + this((World) null); + } + + /** + * Create a new selector. + * + * @param world the world, which may be {@code null} + */ + public EllipsoidRegionSelector(@Nullable World world) { + region = new EllipsoidRegion(world, BlockVector3.ZERO, Vector3.ZERO); + } + + /** + * Create a new selector from the given selector. + * + * @param oldSelector the old selector + */ + public EllipsoidRegionSelector(RegionSelector oldSelector) { + this(checkNotNull(oldSelector).getIncompleteRegion().getWorld()); + if (oldSelector instanceof EllipsoidRegionSelector) { + final EllipsoidRegionSelector ellipsoidRegionSelector = (EllipsoidRegionSelector) oldSelector; + + region = new EllipsoidRegion(ellipsoidRegionSelector.getIncompleteRegion()); + started = ellipsoidRegionSelector.started; + selectedRadius = ellipsoidRegionSelector.selectedRadius; + } else { + Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + BlockVector3 pos1 = oldRegion.getMinimumPoint(); + BlockVector3 pos2 = oldRegion.getMaximumPoint(); + + BlockVector3 center = pos1.add(pos2).divide(2).floor(); + region.setCenter(center); + region.setRadius(pos2.subtract(center).toVector3()); + started = true; + selectedRadius = true; + } + } + + /** + * Create a new selector. + * + * @param world the world + * @param center the center + * @param radius the radius + */ + public EllipsoidRegionSelector(@Nullable World world, BlockVector3 center, Vector3 radius) { + this(world); + + region.setCenter(center); + region.setRadius(radius); + + started = true; + selectedRadius = true; + } + + @Nullable + @Override + public World getWorld() { + return region.getWorld(); + } + + @Override + public void setWorld(@Nullable World world) { + region.setWorld(world); + } + + @Override + public boolean selectPrimary(BlockVector3 position, SelectorLimits limits) { + if (started && position.equals(region.getCenter().toBlockPoint()) && !selectedRadius) { + return false; + } + + region.setCenter(position); + region.setRadius(Vector3.ZERO); + started = true; + selectedRadius = false; + + return true; + } + + @Override + public boolean selectSecondary(BlockVector3 position, SelectorLimits limits) { + if (!started) { + return false; + } + + final Vector3 diff = position.toVector3().subtract(region.getCenter()); + final Vector3 minRadius = diff.getMaximum(diff.multiply(-1.0)); + region.extendRadius(minRadius); + + selectedRadius = true; + + return true; + } + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, BlockVector3 pos) { + if (isDefined()) { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.ellipsoid.explain.primary-area", + TextComponent.of(region.getCenter().toString()), + TextComponent.of(region.getVolume()) + )); + } else { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.ellipsoid.explain.primary", + TextComponent.of(region.getCenter().toString()) + )); + } + + session.describeCUI(player); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, BlockVector3 pos) { + if (isDefined()) { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.ellipsoid.explain.secondary-area", + TextComponent.of(region.getRadius().toString()), + TextComponent.of(region.getVolume()) + )); + } else { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.ellipsoid.explain.secondary", + TextComponent.of(region.getRadius().toString()) + )); + } + + session.describeCUI(player); + } + + @Override + public void explainRegionAdjust(Actor player, LocalSession session) { + session.describeCUI(player); + } + + @Override + public boolean isDefined() { + // started implied by selectedRadius + return selectedRadius; + } + + @Override + public EllipsoidRegion getRegion() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + @Override + public EllipsoidRegion getIncompleteRegion() { + return region; + } + + @Override + public void learnChanges() { + } + + @Override + public void clear() { + region.setCenter(BlockVector3.ZERO); + region.setRadius(Vector3.ZERO); + started = false; + selectedRadius = false; + } + + @Override + public String getTypeName() { + return "ellipsoid"; + } + + @Override + public List getSelectionInfoLines() { + final List lines = new ArrayList<>(); + + final Vector3 center = region.getCenter(); + if (center.lengthSq() > 0) { + lines.add(TranslatableComponent.of("worldedit.selection.ellipsoid.info.center", TextComponent.of(center.toString()) + .clickEvent(ClickEvent.of(ClickEvent.Action.COPY_TO_CLIPBOARD, center.toParserString())) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to copy"))))); + } + + final Vector3 radius = region.getRadius(); + if (radius.lengthSq() > 0) { + lines.add(TranslatableComponent.of("worldedit.selection.ellipsoid.info.radius", TextComponent.of(radius.toString()))); + } + + return lines; + } + + @Override + public long getVolume() { + return region.getVolume(); + } + + @Override + public void describeCUI(LocalSession session, Actor player) { + session.dispatchCUIEvent(player, new SelectionEllipsoidPointEvent(0, region.getCenter().toBlockPoint())); + session.dispatchCUIEvent(player, new SelectionEllipsoidPointEvent(1, region.getRadius().toBlockPoint())); + } + + @Override + public void describeLegacyCUI(LocalSession session, Actor player) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getVolume())); + session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getVolume())); + } + + @Override + public String getLegacyTypeID() { + return "cuboid"; + } + + @Override + public int getProtocolVersion() { + return 1; + } + + @Override + public String getTypeID() { + return "ellipsoid"; + } + + @Override + public BlockVector3 getPrimaryPosition() throws IncompleteRegionException { + return region.getCenter().toBlockPoint(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java new file mode 100644 index 0000000..b369068 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java @@ -0,0 +1,154 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; + +/** + * Creates a {@code CuboidRegion} from a user's selections by expanding + * the region on every right click. + */ +public class ExtendingCuboidRegionSelector extends CuboidRegionSelector { + + /** + * Create a new selector with a {@code null} world. + */ + public ExtendingCuboidRegionSelector() { + super((World) null); + } + + /** + * Create a new selector. + * + * @param world the world, which may be {@code null} + */ + public ExtendingCuboidRegionSelector(@Nullable World world) { + super(world); + } + + /** + * Create a new selector from another one. + * + * @param oldSelector the other selector + */ + public ExtendingCuboidRegionSelector(RegionSelector oldSelector) { + super(oldSelector); + + if (position1 == null || position2 == null) { + return; + } + + position1 = region.getMinimumPoint(); + position2 = region.getMaximumPoint(); + region.setPos1(position1); + region.setPos2(position2); + } + + /** + * Create a new selector. + * + * @param world the world + * @param position1 the first position + * @param position2 the second position + */ + public ExtendingCuboidRegionSelector(@Nullable World world, BlockVector3 position1, BlockVector3 position2) { + this(world); + position1 = position1.getMinimum(position2); + position2 = position1.getMaximum(position2); + region.setPos1(position1); + region.setPos2(position2); + } + + @Override + public boolean selectPrimary(BlockVector3 position, SelectorLimits limits) { + if (position.equals(position1) && position.equals(position2)) { + return false; + } + + position1 = position2 = position; + region.setPos1(position1); + region.setPos2(position2); + return true; + } + + @Override + public boolean selectSecondary(BlockVector3 position, SelectorLimits limits) { + if (position1 == null || position2 == null) { + return selectPrimary(position, limits); + } + + if (region.contains(position)) { + return false; + } + + double x1 = Math.min(position.getX(), position1.getX()); + double y1 = Math.min(position.getY(), position1.getY()); + double z1 = Math.min(position.getZ(), position1.getZ()); + + double x2 = Math.max(position.getX(), position2.getX()); + double y2 = Math.max(position.getY(), position2.getY()); + double z2 = Math.max(position.getZ(), position2.getZ()); + + final BlockVector3 o1 = position1; + final BlockVector3 o2 = position2; + position1 = BlockVector3.at(x1, y1, z1); + position2 = BlockVector3.at(x2, y2, z2); + region.setPos1(position1); + region.setPos2(position2); + + assert region.contains(o1); + assert region.contains(o2); + assert region.contains(position); + + return true; + } + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, BlockVector3 pos) { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.extend.explain.primary", + TextComponent.of(pos.toString()), + TextComponent.of(region.getVolume()) + )); + + explainRegionAdjust(player, session); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, BlockVector3 pos) { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.extend.explain.secondary", + TextComponent.of(pos.toString()), + TextComponent.of(region.getVolume()) + )); + + explainRegionAdjust(player, session); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java new file mode 100644 index 0000000..f7f39e0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java @@ -0,0 +1,287 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionMinMaxEvent; +import com.sk89q.worldedit.internal.cui.SelectionPoint2DEvent; +import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Polygonal2DRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates a {@code Polygonal2DRegion} from a user's selections. + */ +public class Polygonal2DRegionSelector implements RegionSelector, CUIRegion { + + private transient BlockVector3 pos1; + private transient Polygonal2DRegion region; + + /** + * Create a new selector with a {@code null} world. + */ + public Polygonal2DRegionSelector() { + this((World) null); + } + + /** + * Create a new selector with the given world. + * + * @param world the world + */ + public Polygonal2DRegionSelector(@Nullable World world) { + region = new Polygonal2DRegion(world); + } + + /** + * Create a new selector from another one. + * + * @param oldSelector the old selector + */ + public Polygonal2DRegionSelector(RegionSelector oldSelector) { + this(checkNotNull(oldSelector).getIncompleteRegion().getWorld()); + + if (oldSelector instanceof Polygonal2DRegionSelector) { + final Polygonal2DRegionSelector polygonal2DRegionSelector = (Polygonal2DRegionSelector) oldSelector; + + pos1 = polygonal2DRegionSelector.pos1; + region = new Polygonal2DRegion(polygonal2DRegionSelector.region); + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + final int minY = oldRegion.getMinimumPoint().getBlockY(); + final int maxY = oldRegion.getMaximumPoint().getBlockY(); + + List points = oldRegion.polygonize(Integer.MAX_VALUE); + + pos1 = points.get(0).toBlockVector3(minY); + region = new Polygonal2DRegion(oldRegion.getWorld(), points, minY, maxY); + } + } + + /** + * Create a new selector. + * + * @param world the world + * @param points a list of points + * @param minY the minimum Y + * @param maxY the maximum Y + */ + public Polygonal2DRegionSelector(@Nullable World world, List points, int minY, int maxY) { + checkNotNull(points); + + final BlockVector2 pos2D = points.get(0); + pos1 = BlockVector3.at(pos2D.getX(), minY, pos2D.getZ()); + region = new Polygonal2DRegion(world, points, minY, maxY); + } + + @Nullable + @Override + public World getWorld() { + return region.getWorld(); + } + + @Override + public void setWorld(@Nullable World world) { + region.setWorld(world); + } + + @Override + public boolean selectPrimary(BlockVector3 position, SelectorLimits limits) { + if (position.equals(pos1)) { + return false; + } + + pos1 = position; + region = new Polygonal2DRegion(region.getWorld()); + region.addPoint(position); + region.expandY(position.getBlockY()); + + return true; + } + + @Override + public boolean selectSecondary(BlockVector3 position, SelectorLimits limits) { + if (region.size() > 0) { + final List points = region.getPoints(); + + final BlockVector2 lastPoint = points.get(region.size() - 1); + if (lastPoint.getBlockX() == position.getBlockX() && lastPoint.getBlockZ() == position.getBlockZ()) { + return false; + } + + Optional vertexLimit = limits.getPolygonVertexLimit(); + + if (vertexLimit.isPresent() && points.size() > vertexLimit.get()) { + return false; + } + } + + region.addPoint(position); + region.expandY(position.getBlockY()); + + return true; + } + + @Override + public void explainPrimarySelection(Actor player, LocalSession session, BlockVector3 pos) { + player.printInfo(TranslatableComponent.of("worldedit.selection.polygon2d.explain.primary", TextComponent.of(pos.toString()))); + + session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); + session.dispatchCUIEvent(player, new SelectionPoint2DEvent(0, pos, getVolume())); + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, BlockVector3 pos) { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.polygon2d.explain.secondary", + TextComponent.of(region.size()), + TextComponent.of(pos.toString()) + )); + + session.dispatchCUIEvent(player, new SelectionPoint2DEvent(region.size() - 1, pos, getVolume())); + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + @Override + public void explainRegionAdjust(Actor player, LocalSession session) { + session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); + describeCUI(session, player); + } + + @Override + public BlockVector3 getPrimaryPosition() throws IncompleteRegionException { + if (pos1 == null) { + throw new IncompleteRegionException(); + } + + return pos1; + } + + @Override + public Polygonal2DRegion getRegion() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + @Override + public Polygonal2DRegion getIncompleteRegion() { + return region; + } + + @Override + public boolean isDefined() { + return region.size() > 2; + } + + @Override + public void learnChanges() { + BlockVector2 pt = region.getPoints().get(0); + pos1 = BlockVector3.at(pt.getBlockX(), region.getMinimumPoint().getBlockY(), pt.getBlockZ()); + } + + @Override + public void clear() { + pos1 = null; + region = new Polygonal2DRegion(region.getWorld()); + } + + @Override + public String getTypeName() { + return "2Dx1D polygon"; + } + + @Override + public List getSelectionInfoLines() { + return Collections.singletonList(TranslatableComponent.of("worldedit.selection.polygon2d.info", TextComponent.of(region.size()))); + } + + @Override + public long getVolume() { + return region.getVolume(); + } + + /** + * Get the number of points. + * + * @return the number of points + */ + public int getPointCount() { + return region.getPoints().size(); + } + + @Override + public void describeCUI(LocalSession session, Actor player) { + final List points = region.getPoints(); + for (int id = 0; id < points.size(); id++) { + session.dispatchCUIEvent(player, new SelectionPoint2DEvent(id, points.get(id), getVolume())); + } + + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + @Override + public void describeLegacyCUI(LocalSession session, Actor player) { + describeCUI(session, player); + } + + @Override + public int getProtocolVersion() { + return 0; + } + + @Override + public String getTypeID() { + return "polygon2d"; + } + + @Override + public String getLegacyTypeID() { + return "polygon2d"; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java b/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java new file mode 100644 index 0000000..61e46ae --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java @@ -0,0 +1,65 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.sk89q.worldedit.regions.RegionSelector; + +/** + * An enum of default region selector types. + */ +public enum RegionSelectorType { + + CUBOID(CuboidRegionSelector.class), + EXTENDING_CUBOID(ExtendingCuboidRegionSelector.class), + CYLINDER(CylinderRegionSelector.class), + SPHERE(SphereRegionSelector.class), + ELLIPSOID(EllipsoidRegionSelector.class), + POLYGON(Polygonal2DRegionSelector.class), + CONVEX_POLYHEDRON(ConvexPolyhedralRegionSelector.class); + + private final Class selectorClass; + + RegionSelectorType(Class selectorClass) { + this.selectorClass = selectorClass; + } + + /** + * Get the selector class. + * + * @return a selector class + */ + public Class getSelectorClass() { + return selectorClass; + } + + /** + * Create a new selector instance. + * + * @return a selector + */ + public RegionSelector createSelector() { + try { + return getSelectorClass().newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException("Could not create selector", e); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java new file mode 100644 index 0000000..3c25e46 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java @@ -0,0 +1,114 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.selector; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.SelectorLimits; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; + +/** + * Creates a {@code SphereRegion} from a user's selections. + */ +public class SphereRegionSelector extends EllipsoidRegionSelector { + + /** + * Create a new selector with a {@code null world}. + */ + public SphereRegionSelector() { + super(); + } + + /** + * Create a new selector. + * + * @param world the world, which may be {@code null} + */ + public SphereRegionSelector(@Nullable World world) { + super(world); + } + + /** + * Create a new selector from another one. + * + * @param oldSelector the old selector + */ + public SphereRegionSelector(RegionSelector oldSelector) { + super(oldSelector); + if (selectedRadius) { + final Vector3 radius = region.getRadius(); + final double radiusScalar = Math.max(Math.max(radius.getX(), radius.getY()), radius.getZ()); + region.setRadius(Vector3.at(radiusScalar, radiusScalar, radiusScalar)); + } + } + + /** + * Create a new selector. + * + * @param world the world + * @param center the center position + * @param radius the radius + */ + public SphereRegionSelector(@Nullable World world, BlockVector3 center, int radius) { + super(world, center, Vector3.at(radius, radius, radius)); + } + + @Override + public boolean selectSecondary(BlockVector3 position, SelectorLimits limits) { + if (!started) { + return false; + } + + final double radiusScalar = Math.ceil(position.toVector3().distance(region.getCenter())); + region.setRadius(Vector3.at(radiusScalar, radiusScalar, radiusScalar)); + + selectedRadius = true; + + return true; + } + + @Override + public void explainSecondarySelection(Actor player, LocalSession session, BlockVector3 pos) { + if (isDefined()) { + player.printInfo(TranslatableComponent.of( + "worldedit.selection.sphere.explain.secondary-defined", + TextComponent.of(region.getRadius().getX()), + TextComponent.of(region.getVolume()) + )); + } else { + player.printInfo(TranslatableComponent.of("worldedit.selection.sphere.explain.secondary", TextComponent.of(region.getRadius().getX()))); + } + + session.describeCUI(player); + } + + @Override + public String getTypeName() { + return "sphere"; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/selector/limit/PermissiveSelectorLimits.java b/src/main/java/com/sk89q/worldedit/regions/selector/limit/PermissiveSelectorLimits.java new file mode 100644 index 0000000..d6a5b35 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/selector/limit/PermissiveSelectorLimits.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.selector.limit; + +import java.util.Optional; + +/** + * No limits at all. + */ +public class PermissiveSelectorLimits implements SelectorLimits { + + private static final PermissiveSelectorLimits INSTANCE = new PermissiveSelectorLimits(); + + private PermissiveSelectorLimits() { + } + + @Override + public Optional getPolygonVertexLimit() { + return Optional.empty(); + } + + @Override + public Optional getPolyhedronVertexLimit() { + return Optional.empty(); + } + + /** + * Get a static instance. + * + * @return an instance + */ + public static PermissiveSelectorLimits getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/selector/limit/SelectorLimits.java b/src/main/java/com/sk89q/worldedit/regions/selector/limit/SelectorLimits.java new file mode 100644 index 0000000..6b1e30d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/selector/limit/SelectorLimits.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.selector.limit; + +import java.util.Optional; + +/** + * Defines limits for selections. + */ +public interface SelectorLimits { + + /** + * Get the optionally defined vertex limit for polygons. + * + *

If one is not present, then there is no limitation.

+ * + * @return an optional vertex limit + */ + Optional getPolygonVertexLimit(); + + /** + * Get the optionally defined vertex limit for polyhedrons. + * + *

If one is not present, then there is no limitation.

+ * + * @return an optional vertex limit + */ + Optional getPolyhedronVertexLimit(); + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java new file mode 100644 index 0000000..7a28923 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java @@ -0,0 +1,158 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.shape; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BiomeType; + +import java.util.BitSet; + +/** + * Generates solid and hollow shapes according to materials returned by the + * {@link #getBiome} method. + */ +public abstract class ArbitraryBiomeShape { + + private final Region extent; + private final int cacheOffsetX; + private final int cacheOffsetY; + private final int cacheOffsetZ; + @SuppressWarnings("FieldCanBeLocal") + private final int cacheSizeX; + private final int cacheSizeY; + private final int cacheSizeZ; + private final BiomeType[] cache; + private final BitSet isCached; + + public ArbitraryBiomeShape(Region extent) { + this.extent = extent; + + BlockVector3 min = extent.getMinimumPoint(); + BlockVector3 max = extent.getMaximumPoint(); + + cacheOffsetX = min.getBlockX() - 1; + cacheOffsetY = min.getBlockY() - 1; + cacheOffsetZ = min.getBlockZ() - 1; + + cacheSizeX = max.getX() - cacheOffsetX + 2; + cacheSizeY = max.getY() - cacheOffsetY + 2; + cacheSizeZ = max.getZ() - cacheOffsetZ + 2; + + cache = new BiomeType[cacheSizeX * cacheSizeY * cacheSizeZ]; + isCached = new BitSet(cache.length); + } + + protected Iterable getExtent() { + return extent; + } + + /** + * Override this function to specify the shape to generate. + * + * @param x X coordinate to be queried + * @param z Z coordinate to be queried + * @param defaultBaseBiome The default biome for the current column. + * @return material to place or null to not place anything. + */ + protected abstract BiomeType getBiome(int x, int y, int z, BiomeType defaultBaseBiome); + + private BiomeType getBiomeCached(int x, int y, int z, BiomeType baseBiome) { + final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ; + + if (!isCached.get(index)) { + final BiomeType material = getBiome(x, y, z, baseBiome); + isCached.set(index); + cache[index] = material; + return material; + } + + return cache[index]; + } + + private boolean isOutside(int x, int y, int z, BiomeType baseBiome) { + return getBiomeCached(x, y, z, baseBiome) == null; + } + + /** + * Generates the shape. + * + * @param editSession The EditSession to use. + * @param baseBiome The default biome type. + * @param hollow Specifies whether to generate a hollow shape. + * @return number of affected blocks. + */ + public int generate(EditSession editSession, BiomeType baseBiome, boolean hollow) { + int affected = 0; + + for (BlockVector3 position : getExtent()) { + int x = position.getBlockX(); + int y = position.getBlockY(); + int z = position.getBlockZ(); + + if (!hollow) { + final BiomeType material = getBiome(x, y, z, baseBiome); + if (material != null) { + editSession.getWorld().setBiome(position, material); + ++affected; + } + + continue; + } + + final BiomeType material = getBiomeCached(x, y, z, baseBiome); + if (material == null) { + continue; + } + + if (!shouldDraw(x, y, z, material)) { + continue; + } + + editSession.getWorld().setBiome(position, material); + ++affected; + } + + return affected; + } + + private boolean shouldDraw(int x, int y, int z, BiomeType material) { + // we should draw this if the surrounding blocks fall outside the shape, + // this position will form an edge of the hull + if (isOutside(x + 1, y, z, material)) { + return true; + } + if (isOutside(x - 1, y, z, material)) { + return true; + } + if (isOutside(x, y, z + 1, material)) { + return true; + } + if (isOutside(x, y, z - 1, material)) { + return true; + } + if (isOutside(x, y + 1, z, material)) { + return true; + } + return isOutside(x, y - 1, z, material); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java new file mode 100644 index 0000000..60ccf64 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java @@ -0,0 +1,184 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.shape; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BaseBlock; + +/** + * Generates solid and hollow shapes according to materials returned by the + * {@link #getMaterial} method. + */ +public abstract class ArbitraryShape { + + protected final Region extent; + + private final int cacheOffsetX; + private final int cacheOffsetY; + private final int cacheOffsetZ; + private final int cacheSizeX; + private final int cacheSizeY; + private final int cacheSizeZ; + + /** + * Cache for expression results. + * + *

+ * Cache entries: + * 0 = unknown + * -1 = outside + * 1 = inside + *

+ */ + private final byte[] cache; + + public ArbitraryShape(Region extent) { + this.extent = extent; + + BlockVector3 min = extent.getMinimumPoint(); + BlockVector3 max = extent.getMaximumPoint(); + + cacheOffsetX = min.getBlockX() - 1; + cacheOffsetY = min.getBlockY() - 1; + cacheOffsetZ = min.getBlockZ() - 1; + + cacheSizeX = max.getX() - cacheOffsetX + 2; + cacheSizeY = max.getY() - cacheOffsetY + 2; + cacheSizeZ = max.getZ() - cacheOffsetZ + 2; + + cache = new byte[cacheSizeX * cacheSizeY * cacheSizeZ]; + } + + protected Region getExtent() { + return extent; + } + + /** + * Override this function to specify the shape to generate. + * + * @param x X coordinate to be queried + * @param y Y coordinate to be queried + * @param z Z coordinate to be queried + * @param defaultMaterial The material returned by the pattern for the current block. + * @return material to place or null to not place anything. + */ + protected abstract BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial); + + /** + * Generates the shape. + * + * @param editSession The EditSession to use. + * @param pattern The pattern to generate default materials from. + * @param hollow Specifies whether to generate a hollow shape. + * @return number of affected blocks. + * @throws MaxChangedBlocksException if the maximum blocks changed is exceeded + */ + public int generate(EditSession editSession, Pattern pattern, boolean hollow) throws MaxChangedBlocksException { + int affected = 0; + + for (BlockVector3 position : getExtent()) { + int x = position.getBlockX(); + int y = position.getBlockY(); + int z = position.getBlockZ(); + + if (!hollow) { + BaseBlock material = getMaterial(x, y, z, pattern.applyBlock(position)); + if (material != null && editSession.setBlock(position, material)) { + ++affected; + } + + continue; + } + + BaseBlock material = getMaterial(x, y, z, pattern.applyBlock(position)); + if (material == null) { + final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ; + cache[index] = -1; + continue; + } + + boolean draw = false; + do { + if (!isInsideCached(x + 1, y, z, pattern)) { + draw = true; + break; + } + if (!isInsideCached(x - 1, y, z, pattern)) { + draw = true; + break; + } + if (!isInsideCached(x, y, z + 1, pattern)) { + draw = true; + break; + } + if (!isInsideCached(x, y, z - 1, pattern)) { + draw = true; + break; + } + if (!isInsideCached(x, y + 1, z, pattern)) { + draw = true; + break; + } + if (!isInsideCached(x, y - 1, z, pattern)) { + draw = true; + break; + } + } while (false); + + if (!draw) { + continue; + } + + if (editSession.setBlock(position, material)) { + ++affected; + } + } + + return affected; + } + + private boolean isInsideCached(int x, int y, int z, Pattern pattern) { + final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ; + + switch (cache[index]) { + case 0: + BaseBlock mat = getMaterial(x, y, z, pattern.applyBlock(BlockVector3.at(x, y, z))); + if (mat == null) { + cache[index] = -1; + return false; + } + cache[index] = 1; + return true; + + case -1: + // outside + return false; + + default: + // inside + return true; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/shape/RegionShape.java b/src/main/java/com/sk89q/worldedit/regions/shape/RegionShape.java new file mode 100644 index 0000000..a662cdf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/shape/RegionShape.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.shape; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BaseBlock; + +/** + * Generates solid and hollow shapes according to materials returned by the + * {@link #getMaterial} method. + */ +public class RegionShape extends ArbitraryShape { + + public RegionShape(Region extent) { + super(extent); + } + + @Override + protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { + if (!this.extent.contains(BlockVector3.at(x, y, z))) { + return null; + } + + return defaultMaterial; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java b/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java new file mode 100644 index 0000000..56763d3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java @@ -0,0 +1,89 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.regions.shape; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.expression.ExpressionEnvironment; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.world.registry.LegacyMapper; + +public class WorldEditExpressionEnvironment implements ExpressionEnvironment { + + private final Vector3 unit; + private final Vector3 zero2; + private Vector3 current = Vector3.ZERO; + private final Extent extent; + + public WorldEditExpressionEnvironment(Extent extent, Vector3 unit, Vector3 zero) { + this.extent = extent; + this.unit = unit; + this.zero2 = zero.add(0.5, 0.5, 0.5); + } + + public BlockVector3 toWorld(double x, double y, double z) { + // unscale, unoffset, round-nearest + return Vector3.at(x, y, z).multiply(unit).add(zero2).toBlockPoint(); + } + + public Vector3 toWorldRel(double x, double y, double z) { + return current.add(x, y, z); + } + + private int getLegacy(BlockVector3 position, int index) { + final int[] legacy = LegacyMapper.getInstance().getLegacyFromBlock(extent.getBlock(position).toImmutableState()); + return legacy == null ? 0 : legacy[index]; + } + + @Override + public int getBlockType(double x, double y, double z) { + return getLegacy(toWorld(x, y, z), 0); + } + + @Override + public int getBlockData(double x, double y, double z) { + return getLegacy(toWorld(x, y, z), 1); + } + + @Override + public int getBlockTypeAbs(double x, double y, double z) { + return getLegacy(BlockVector3.at(x, y, z), 0); + } + + @Override + public int getBlockDataAbs(double x, double y, double z) { + return getLegacy(BlockVector3.at(x, y, z), 1); + } + + @Override + public int getBlockTypeRel(double x, double y, double z) { + return getLegacy(toWorldRel(x, y, z).toBlockPoint(), 0); + } + + @Override + public int getBlockDataRel(double x, double y, double z) { + return getLegacy(toWorldRel(x, y, z).toBlockPoint(), 1); + } + + public void setCurrentBlock(Vector3 current) { + this.current = current; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/registry/Category.java b/src/main/java/com/sk89q/worldedit/registry/Category.java new file mode 100644 index 0000000..b6aa99d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/registry/Category.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.registry; + +import java.util.HashSet; +import java.util.Set; + +public abstract class Category { + private final Set set = new HashSet<>(); + protected final String id; + private boolean empty = true; + + protected Category(final String id) { + this.id = id; + } + + public final String getId() { + return this.id; + } + + public final Set getAll() { + if (this.empty) { + this.set.addAll(this.load()); + this.empty = false; + } + return this.set; + } + + protected abstract Set load(); + + /** + * Checks if this category contains {@code object}. + * + * @param object the object + * @return {@code true} if this category contains the object + */ + public boolean contains(final T object) { + return this.getAll().contains(object); + } + + public void invalidateCache() { + this.set.clear(); + this.empty = true; + } + + @Override + public String toString() { + return getId(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/registry/Keyed.java b/src/main/java/com/sk89q/worldedit/registry/Keyed.java new file mode 100644 index 0000000..faae292 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/registry/Keyed.java @@ -0,0 +1,31 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.registry; + +/** + * Represents an objects that can be added to a registry and referenced by an id which is unique within its registry. + */ +public interface Keyed { + /** + * The id of this object in the registry. Must be unique, and lowercase. Certain registries (e.g Namespaced ones) may have additional restrictions. + * @return an id + */ + String getId(); +} diff --git a/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java b/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java new file mode 100644 index 0000000..28b6734 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + +public final class NamespacedRegistry extends Registry { + private static final String MINECRAFT_NAMESPACE = "minecraft"; + private final Set knownNamespaces = new HashSet<>(); + private final String defaultNamespace; + + public NamespacedRegistry(final String name) { + this(name, MINECRAFT_NAMESPACE); + } + + public NamespacedRegistry(final String name, final boolean checkInitialized) { + this(name, MINECRAFT_NAMESPACE, checkInitialized); + } + + public NamespacedRegistry(final String name, final String defaultNamespace) { + this(name, defaultNamespace, false); + } + + public NamespacedRegistry(final String name, final String defaultNamespace, final boolean checkInitialized) { + super(name, checkInitialized); + this.defaultNamespace = defaultNamespace; + } + + @Nullable + @Override + public V get(final String key) { + return super.get(this.orDefaultNamespace(key)); + } + + @Override + public V register(final String key, final V value) { + requireNonNull(key, "key"); + final int i = key.indexOf(':'); + checkState(i > 0, "key is not namespaced"); + final V registered = super.register(key, value); + knownNamespaces.add(key.substring(0, i)); + return registered; + } + + /** + * Get a set of the namespaces of all registered keys. + * + * @return set of namespaces + */ + public Set getKnownNamespaces() { + return Collections.unmodifiableSet(knownNamespaces); + } + + /** + * Get the default namespace for this registry. + * + * @return the default namespace + */ + public String getDefaultNamespace() { + return defaultNamespace; + } + + private String orDefaultNamespace(final String key) { + if (key.indexOf(':') == -1) { + return defaultNamespace + ':' + key; + } + return key; + } +} diff --git a/src/main/java/com/sk89q/worldedit/registry/Registry.java b/src/main/java/com/sk89q/worldedit/registry/Registry.java new file mode 100644 index 0000000..27f781a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/registry/Registry.java @@ -0,0 +1,80 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.registry; + +import com.sk89q.worldedit.WorldEdit; + +import javax.annotation.Nullable; +import java.util.*; + +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + +public class Registry implements Iterable { + private final Map map = new HashMap<>(); + private final String name; + private final boolean checkInitialized; + + public Registry(final String name) { + this(name, false); + } + + public Registry(final String name, final boolean checkInitialized) { + this.name = name; + this.checkInitialized = checkInitialized; + } + + public String getName() { + return name; + } + + @Nullable + public V get(final String key) { + checkState(key.equals(key.toLowerCase(Locale.ROOT)), "key must be lowercase: %s", key); + if (this.checkInitialized) { + checkState(WorldEdit.getInstance().getPlatformManager().isInitialized(), + "WorldEdit is not initialized yet."); + } + return this.map.get(key); + } + + public V register(final String key, final V value) { + requireNonNull(key, "key"); + requireNonNull(value, "value"); + checkState(key.equals(key.toLowerCase(Locale.ROOT)), "key must be lowercase: %s", key); + checkState(!this.map.containsKey(key), "key '%s' already has an associated %s", key, this.name); + this.map.put(key, value); + return value; + } + + public Set keySet() { + return Collections.unmodifiableSet(this.map.keySet()); + } + + public Collection values() { + return Collections.unmodifiableCollection(this.map.values()); + } + + @Override + public Iterator iterator() { + return this.map.values().iterator(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/registry/state/AbstractProperty.java b/src/main/java/com/sk89q/worldedit/registry/state/AbstractProperty.java new file mode 100644 index 0000000..ff82889 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/registry/state/AbstractProperty.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.registry.state; + +import java.util.List; + +public abstract class AbstractProperty implements Property { + + private final String name; + private final List values; + + public AbstractProperty(final String name, final List values) { + this.name = name; + this.values = values; + } + + @Override + public List getValues() { + return this.values; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{name=" + name + "}"; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Property)) { + return false; + } + return getName().equals(((Property) obj).getName()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/registry/state/BooleanProperty.java b/src/main/java/com/sk89q/worldedit/registry/state/BooleanProperty.java new file mode 100644 index 0000000..036b318 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/registry/state/BooleanProperty.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.registry.state; + +import javax.annotation.Nullable; +import java.util.List; + +public class BooleanProperty extends AbstractProperty { + + public BooleanProperty(final String name, final List values) { + super(name, values); + } + + @Nullable + @Override + public Boolean getValueFor(String string) { + boolean val = Boolean.parseBoolean(string); + if (!getValues().contains(val)) { + throw new IllegalArgumentException("Invalid boolean value: " + string + ". Must be in " + getValues().toString()); + } + return val; + } +} diff --git a/src/main/java/com/sk89q/worldedit/registry/state/DirectionalProperty.java b/src/main/java/com/sk89q/worldedit/registry/state/DirectionalProperty.java new file mode 100644 index 0000000..2acd0d0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/registry/state/DirectionalProperty.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.registry.state; + +import com.sk89q.worldedit.util.Direction; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Locale; + +public class DirectionalProperty extends AbstractProperty { + + public DirectionalProperty(final String name, final List values) { + super(name, values); + } + + @Nullable + @Override + public Direction getValueFor(final String string) { + Direction direction = Direction.valueOf(string.toUpperCase(Locale.ROOT)); + if (!getValues().contains(direction)) { + throw new IllegalArgumentException("Invalid direction value: " + string + ". Must be in " + getValues().toString()); + } + return direction; + } +} diff --git a/src/main/java/com/sk89q/worldedit/registry/state/EnumProperty.java b/src/main/java/com/sk89q/worldedit/registry/state/EnumProperty.java new file mode 100644 index 0000000..cc60d33 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/registry/state/EnumProperty.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.registry.state; + +import javax.annotation.Nullable; +import java.util.List; + +public class EnumProperty extends AbstractProperty { + + public EnumProperty(final String name, final List values) { + super(name, values); + } + + @Nullable + @Override + public String getValueFor(String string) { + if (!getValues().contains(string)) { + throw new IllegalArgumentException("Invalid value: " + string + ". Must be in " + getValues().toString()); + } + return string; + } +} diff --git a/src/main/java/com/sk89q/worldedit/registry/state/IntegerProperty.java b/src/main/java/com/sk89q/worldedit/registry/state/IntegerProperty.java new file mode 100644 index 0000000..531566a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/registry/state/IntegerProperty.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.registry.state; + +import javax.annotation.Nullable; +import java.util.List; + +public class IntegerProperty extends AbstractProperty { + + public IntegerProperty(final String name, final List values) { + super(name, values); + } + + @Nullable + @Override + public Integer getValueFor(String string) { + try { + int val = Integer.parseInt(string); + if (!getValues().contains(val)) { + throw new IllegalArgumentException("Invalid int value: " + string + ". Must be in " + getValues().toString()); + } + return val; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid int value: " + string + ". Not an int."); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/registry/state/Property.java b/src/main/java/com/sk89q/worldedit/registry/state/Property.java new file mode 100644 index 0000000..d3f0f08 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/registry/state/Property.java @@ -0,0 +1,56 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.registry.state; + +import java.util.List; +import javax.annotation.Nullable; + +/** + * Describes a state property of a block. + * + *

Example states include "variant" (indicating material or type) and + * "facing" (indicating orientation).

+ */ +public interface Property { + + /** + * Returns the name of this state. + * + * @return The state name + */ + String getName(); + + /** + * Return a list of available values for this state. + * + * @return the list of state values + */ + List getValues(); + + /** + * Gets the value for the given string, or null. + * + * @param string The string + * @return The value, or null + * @throws IllegalArgumentException When the value is invalid. + */ + @Nullable + T getValueFor(String string) throws IllegalArgumentException; +} diff --git a/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java b/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java new file mode 100644 index 0000000..f35b760 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java @@ -0,0 +1,272 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.scripting; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.command.InsufficientArgumentsException; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.input.DisallowedUsageException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.expression.invoke.ReturnException; +import com.sk89q.worldedit.session.request.Request; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.util.io.file.FilenameException; +import com.sk89q.worldedit.world.block.BaseBlock; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * The context given to scripts. + */ +public class CraftScriptContext extends CraftScriptEnvironment { + + private final List editSessions = new ArrayList<>(); + private final String[] args; + + public CraftScriptContext(WorldEdit controller, + Platform server, LocalConfiguration config, + LocalSession session, Player player, String[] args) { + super(controller, server, config, session, player); + this.args = args; + } + + /** + * Get an edit session. Every subsequent call returns a new edit session. + * Usually you only need to use one edit session. + * + * @return an edit session + */ + public EditSession remember() { + EditSession editSession = controller.newEditSessionBuilder() + .locatableActor(player) + .maxBlocks(session.getBlockChangeLimit()) + .blockBag(session.getBlockBag(player)) + .build(); + Request.request().setEditSession(editSession); + editSession.enableStandardMode(); + editSessions.add(editSession); + return editSession; + } + + /** + * Get the player. + * + * @return the calling player + */ + public Player getPlayer() { + return player; + } + + /** + * Get the player's session. + * + * @return a session + */ + public LocalSession getSession() { + return session; + } + + /** + * Get the configuration for WorldEdit. + * + * @return the configuration + */ + public LocalConfiguration getConfiguration() { + return config; + } + + /** + * Get a list of edit sessions that have been created. + * + * @return a list of created {@code EditSession}s + */ + public List getEditSessions() { + return Collections.unmodifiableList(editSessions); + } + + /** + * Print a regular message to the user. + * + * @param message a message + */ + public void print(String message) { + player.printInfo(TextComponent.of(message)); + } + + /** + * Print an error message to the user. + * + * @param message a message + */ + public void error(String message) { + player.printError(TextComponent.of(message)); + } + + /** + * Print a raw message to the user. + * + * @param message a message + */ + public void printRaw(String message) { + player.print(TextComponent.of(message)); + } + + /** + * Checks to make sure that there are enough but not too many arguments. + * + * @param min a number of arguments + * @param max -1 for no maximum + * @param usage usage string + * @throws InsufficientArgumentsException if the arguments are not "sufficiently" good + */ + public void checkArgs(int min, int max, String usage) + throws InsufficientArgumentsException { + if (args.length <= min || (max != -1 && args.length - 1 > max)) { + throw new InsufficientArgumentsException(TranslatableComponent.of("worldedit.error.incorrect-usage", TextComponent.of(usage))); + } + } + + /** + * Immediately terminate execution of the script, but without a failure message. + * + * @implNote This exits by throwing an exception, which if caught will prevent + * the script from exiting + */ + public void exit() { + throw new ReturnException(null); + } + + /** + * Get an item from an item name or an item ID number. + * + * @param input input to parse + * @param allAllowed true to ignore blacklists + * @return a block + * @throws NoMatchException if no block was found + * @throws DisallowedUsageException if the block is disallowed + */ + public BaseBlock getBlock(String input, boolean allAllowed) throws WorldEditException { + ParserContext context = new ParserContext(); + context.setActor(player); + context.setWorld(player.getWorld()); + context.setSession(session); + context.setRestricted(!allAllowed); + context.setPreferringWildcard(false); + + return controller.getBlockFactory().parseFromListInput(input, context).stream().findFirst().orElse(null); + } + + /** + * Get a block. + * + * @param id the type Id + * @return a block + * @throws NoMatchException if no block was found + * @throws DisallowedUsageException if the block is disallowed + */ + public BaseBlock getBlock(String id) throws WorldEditException { + return getBlock(id, false); + } + + /** + * Get a list of blocks as a set. This returns a Pattern. + * + * @param list the input + * @return pattern + * @throws NoMatchException if the pattern was invalid + * @throws DisallowedUsageException if the block is disallowed + */ + public Pattern getBlockPattern(String list) throws WorldEditException { + ParserContext context = new ParserContext(); + context.setActor(player); + context.setWorld(player.getWorld()); + context.setSession(session); + return controller.getPatternFactory().parseFromInput(list, context); + } + + /** + * Get a list of blocks as a set. + * + * @param list a list + * @param allBlocksAllowed true if all blocks are allowed + * @return set + * @throws NoMatchException if the blocks couldn't be found + * @throws DisallowedUsageException if the block is disallowed + */ + public Set getBlocks(String list, boolean allBlocksAllowed) throws WorldEditException { + ParserContext context = new ParserContext(); + context.setActor(player); + context.setWorld(player.getWorld()); + context.setSession(session); + context.setRestricted(!allBlocksAllowed); + return controller.getBlockFactory().parseFromListInput(list, context); + } + + /** + * Gets the path to a file for opening. This method will check to see if the + * filename has valid characters and has an extension. It also prevents + * directory traversal exploits by checking the root directory and the file + * directory. On success, a {@code java.io.File} object will be + * returned. + * + *

Use this method if you need to read a file from a directory.

+ * + * @param folder sub-directory to look in + * @param filename filename (user-submitted) + * @param defaultExt default extension to append if there is none + * @param exts list of extensions for file open dialog, null for no filter + * @return a file + * @throws FilenameException if there is a problem with the name of the file + */ + public File getSafeOpenFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException { + File dir = controller.getWorkingDirectoryPath(folder).toFile(); + return controller.getSafeOpenFile(player, dir, filename, defaultExt, exts); + } + + /** + * Gets the path to a file for saving. This method will check to see if the + * filename has valid characters and has an extension. It also prevents + * directory traversal exploits by checking the root directory and the file + * directory. On success, a {@code java.io.File} object will be + * returned. + * + *

Use this method if you need to read a file from a directory.

+ * + * @param folder sub-directory to look in + * @param filename filename (user-submitted) + * @param defaultExt default extension to append if there is none + * @param exts list of extensions for file save dialog, null for no filter + * @return a file + * @throws FilenameException if there is a problem with the name of the file + */ + public File getSafeSaveFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException { + File dir = controller.getWorkingDirectoryPath(folder).toFile(); + return controller.getSafeSaveFile(player, dir, filename, defaultExt, exts); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEngine.java b/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEngine.java new file mode 100644 index 0000000..3d3d3f2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEngine.java @@ -0,0 +1,32 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.scripting; + +import java.util.Map; +import javax.script.ScriptException; + +public interface CraftScriptEngine { + void setTimeLimit(int milliseconds); + + int getTimeLimit(); + + Object evaluate(String script, String filename, Map args) + throws ScriptException, Throwable; +} diff --git a/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEnvironment.java b/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEnvironment.java new file mode 100644 index 0000000..1068477 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/scripting/CraftScriptEnvironment.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.scripting; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Platform; + +public abstract class CraftScriptEnvironment { + + protected WorldEdit controller; + protected Player player; + protected LocalConfiguration config; + protected LocalSession session; + protected Platform server; + + public CraftScriptEnvironment(WorldEdit controller, Platform server, LocalConfiguration config, LocalSession session, Player player) { + this.controller = controller; + this.player = player; + this.config = config; + this.server = server; + this.session = session; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java b/src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java new file mode 100644 index 0000000..8a0e1a1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java @@ -0,0 +1,32 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.scripting; + +import org.mozilla.javascript.ClassShutter; + +/** + * Hides Minecraft's obfuscated names from scripts. + */ +class MinecraftHidingClassShutter implements ClassShutter { + @Override + public boolean visibleToScripts(String fullClassName) { + return fullClassName.contains(".") || fullClassName.length() >= 4; + } +} diff --git a/src/main/java/com/sk89q/worldedit/scripting/RhinoContextFactory.java b/src/main/java/com/sk89q/worldedit/scripting/RhinoContextFactory.java new file mode 100644 index 0000000..fc9f7e0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/scripting/RhinoContextFactory.java @@ -0,0 +1,77 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.scripting; + +import org.mozilla.javascript.Callable; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ContextFactory; +import org.mozilla.javascript.Scriptable; + +public class RhinoContextFactory extends ContextFactory { + + protected int timeLimit; + + public RhinoContextFactory(int timeLimit) { + this.timeLimit = timeLimit; + } + + @Override + protected Context makeContext() { + RhinoContext cx = new RhinoContext(this); + try { + // Try to set ES6 compat flag (since 1.7.7) + Context.class.getDeclaredField("VERSION_ES6"); + cx.setLanguageVersion(RhinoContext.VERSION_ES6); + } catch (NoSuchFieldException e) { + // best we can do, compatible with 1.7R2 that many people probably use + cx.setLanguageVersion(Context.VERSION_1_7); + } + cx.setInstructionObserverThreshold(10000); + return cx; + } + + @Override + protected void observeInstructionCount(Context cx, int instructionCount) { + RhinoContext mcx = (RhinoContext) cx; + long currentTime = System.currentTimeMillis(); + + if (currentTime - mcx.startTime > timeLimit) { + throw new Error("Script timed out (" + timeLimit + "ms)"); + } + } + + @Override + protected Object doTopCall(Callable callable, Context cx, Scriptable scope, + Scriptable thisObj, Object[] args) { + RhinoContext mcx = (RhinoContext) cx; + mcx.startTime = System.currentTimeMillis(); + + return super.doTopCall(callable, cx, scope, thisObj, args); + } + + private static class RhinoContext extends Context { + long startTime; + + private RhinoContext(ContextFactory factory) { + super(factory); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java b/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java new file mode 100644 index 0000000..ee9e65a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java @@ -0,0 +1,90 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.scripting; + +import com.sk89q.worldedit.WorldEditException; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ImporterTopLevel; +import org.mozilla.javascript.JavaScriptException; +import org.mozilla.javascript.RhinoException; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.WrappedException; + +import java.util.Map; +import javax.script.ScriptException; + +public class RhinoCraftScriptEngine implements CraftScriptEngine { + private int timeLimit; + + @Override + public void setTimeLimit(int milliseconds) { + timeLimit = milliseconds; + } + + @Override + public int getTimeLimit() { + return timeLimit; + } + + @Override + public Object evaluate(String script, String filename, Map args) throws Throwable { + RhinoContextFactory factory = new RhinoContextFactory(timeLimit); + Context cx = factory.enterContext(); + cx.setClassShutter(new MinecraftHidingClassShutter()); + ScriptableObject scriptable = new ImporterTopLevel(cx); + Scriptable scope = cx.initStandardObjects(scriptable); + + for (Map.Entry entry : args.entrySet()) { + ScriptableObject.putProperty(scope, entry.getKey(), + Context.javaToJS(entry.getValue(), scope)); + } + try { + return cx.evaluateString(scope, script, filename, 1, null); + } catch (Error e) { + throw new ScriptException(e.getMessage()); + } catch (RhinoException e) { + if (e instanceof WrappedException) { + Throwable cause = e.getCause(); + if (cause instanceof WorldEditException) { + throw cause; + } + } + + String msg; + int line = (line = e.lineNumber()) == 0 ? -1 : line; + + if (e instanceof JavaScriptException) { + msg = String.valueOf(((JavaScriptException) e).getValue()); + } else { + msg = e.getMessage(); + } + + ScriptException scriptException = + new ScriptException(msg, e.sourceName(), line); + scriptException.initCause(e); + + throw scriptException; + } finally { + Context.exit(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java b/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java new file mode 100644 index 0000000..9cd8087 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java @@ -0,0 +1,89 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.transform.Identity; +import com.sk89q.worldedit.math.transform.Transform; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Holds the clipboard and the current transform on the clipboard. + */ +public class ClipboardHolder { + + private final Clipboard clipboard; + private Transform transform = new Identity(); + + /** + * Create a new instance with the given clipboard. + * + * @param clipboard the clipboard + */ + public ClipboardHolder(Clipboard clipboard) { + checkNotNull(clipboard); + this.clipboard = clipboard; + } + + /** + * Get the clipboard. + * + *

+ * If there is a transformation applied, the returned clipboard will + * not contain its effect. + *

+ * + * @return the clipboard + */ + public Clipboard getClipboard() { + return clipboard; + } + + /** + * Set the transform. + * + * @param transform the transform + */ + public void setTransform(Transform transform) { + checkNotNull(transform); + this.transform = transform; + } + + /** + * Get the transform. + * + * @return the transform + */ + public Transform getTransform() { + return transform; + } + + /** + * Create a builder for an operation to paste this clipboard. + * + * @return a builder + */ + public PasteBuilder createPaste(Extent targetExtent) { + return new PasteBuilder(this, targetExtent); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/session/MissingSessionException.java b/src/main/java/com/sk89q/worldedit/session/MissingSessionException.java new file mode 100644 index 0000000..b923abe --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/MissingSessionException.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session; + +/** + * Raised when the session is missing. + */ +public class MissingSessionException extends Exception { + + public MissingSessionException() { + } + + public MissingSessionException(String message) { + super(message); + } + + public MissingSessionException(String message, Throwable cause) { + super(message, cause); + } + + public MissingSessionException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java b/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java new file mode 100644 index 0000000..8724633 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java @@ -0,0 +1,147 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.transform.BlockTransformExtent; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.MaskIntersection; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.transform.Transform; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Builds an operation to paste the contents of a clipboard. + */ +public class PasteBuilder { + + private final Clipboard clipboard; + private final Transform transform; + private final Extent targetExtent; + + private Mask sourceMask = Masks.alwaysTrue(); + + private BlockVector3 to = BlockVector3.ZERO; + private boolean ignoreAirBlocks; + private boolean copyEntities = true; // default because it used to be this way + private boolean copyBiomes; + + /** + * Create a new instance. + * + * @param holder the clipboard holder + * @param targetExtent an extent + */ + PasteBuilder(ClipboardHolder holder, Extent targetExtent) { + checkNotNull(holder); + checkNotNull(targetExtent); + this.clipboard = holder.getClipboard(); + this.transform = holder.getTransform(); + this.targetExtent = targetExtent; + } + + /** + * Set the target location. + * + * @param to the target location + * @return this builder instance + */ + public PasteBuilder to(BlockVector3 to) { + this.to = to; + return this; + } + + /** + * Set a custom mask of blocks to ignore from the source. + * This provides a more flexible alternative to {@link #ignoreAirBlocks(boolean)}, for example + * one might want to ignore structure void if copying a Minecraft Structure, etc. + * + * @param sourceMask the mask for the source + * @return this builder instance + */ + public PasteBuilder maskSource(Mask sourceMask) { + if (sourceMask == null) { + this.sourceMask = Masks.alwaysTrue(); + return this; + } + this.sourceMask = sourceMask; + return this; + } + + /** + * Set whether air blocks in the source are skipped over when pasting. + * + * @return this builder instance + */ + public PasteBuilder ignoreAirBlocks(boolean ignoreAirBlocks) { + this.ignoreAirBlocks = ignoreAirBlocks; + return this; + } + + /** + * Set whether the copy should include source entities. + * Note that this is true by default for legacy reasons. + * + * @param copyEntities if entities should be copied + * @return this builder instance + */ + public PasteBuilder copyEntities(boolean copyEntities) { + this.copyEntities = copyEntities; + return this; + } + + /** + * Set whether the copy should include source biomes (if available). + * + * @param copyBiomes if biomes should be copied + * @return this builder instance + */ + public PasteBuilder copyBiomes(boolean copyBiomes) { + this.copyBiomes = copyBiomes; + return this; + } + + /** + * Build the operation. + * + * @return the operation + */ + public Operation build() { + BlockTransformExtent extent = new BlockTransformExtent(clipboard, transform); + ForwardExtentCopy copy = new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(), targetExtent, to); + copy.setTransform(transform); + if (ignoreAirBlocks) { + copy.setSourceMask(sourceMask == Masks.alwaysTrue() ? new ExistingBlockMask(clipboard) + : new MaskIntersection(sourceMask, new ExistingBlockMask(clipboard))); + } else { + copy.setSourceMask(sourceMask); + } + copy.setCopyingEntities(copyEntities); + copy.setCopyingBiomes(copyBiomes && clipboard.hasBiomes()); + return copy; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/session/SessionKey.java b/src/main/java/com/sk89q/worldedit/session/SessionKey.java new file mode 100644 index 0000000..de88aec --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/SessionKey.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session; + +import com.sk89q.worldedit.util.Identifiable; + +import javax.annotation.Nullable; + +/** + * Provides information about a session. + * + *

A reference for this object may be kept around for a long time.

+ */ +public interface SessionKey extends Identifiable { + + /** + * Get the name for this session, if one is available, so that it can + * be referred to by others. + * + * @return a name or {@code null} + */ + @Nullable + String getName(); + + /** + * Return whether the session is still active. Sessions that are inactive + * for a prolonged amount of time may be removed. If this method + * always returns {@code false}, the the related session may never + * be stored. + * + *

This method may be called from any thread, so this call + * must be thread safe.

+ * + * @return true if active + */ + boolean isActive(); + + /** + * Return whether this session should be persisted. + * + * @return true if persistent + */ + boolean isPersistent(); + +} diff --git a/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/src/main/java/com/sk89q/worldedit/session/SessionManager.java new file mode 100644 index 0000000..c1931a5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -0,0 +1,403 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.tool.InvalidToolBindException; +import com.sk89q.worldedit.command.tool.NavigationWand; +import com.sk89q.worldedit.command.tool.SelectionWand; +import com.sk89q.worldedit.command.tool.Tool; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent; +import com.sk89q.worldedit.event.platform.SessionIdleEvent; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.session.storage.JsonFileSessionStore; +import com.sk89q.worldedit.session.storage.SessionStore; +import com.sk89q.worldedit.session.storage.VoidStore; +import com.sk89q.worldedit.util.concurrency.EvenMoreExecutors; +import com.sk89q.worldedit.util.eventbus.Subscribe; +import com.sk89q.worldedit.world.gamemode.GameModes; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Session manager for WorldEdit. + * + *

Get a reference to one from {@link WorldEdit}.

+ * + *

While this class is thread-safe, the returned session may not be.

+ */ +public class SessionManager { + + public static int EXPIRATION_GRACE = 10 * 60 * 1000; + private static final int FLUSH_PERIOD = 1000 * 30; + private static final ListeningExecutorService executorService = MoreExecutors.listeningDecorator( + EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 5, "WorldEdit Session Saver - %s")); + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final Set warnedInvalidTool = Collections.newSetFromMap(new ConcurrentHashMap<>()); + + private final Timer timer = new Timer("WorldEdit Session Manager"); + private final WorldEdit worldEdit; + private final Map sessions = new HashMap<>(); + private SessionStore store = new VoidStore(); + + /** + * Create a new session manager. + * + * @param worldEdit a WorldEdit instance + */ + public SessionManager(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + + worldEdit.getEventBus().register(this); + timer.schedule(new SessionTracker(), FLUSH_PERIOD, FLUSH_PERIOD); + } + + /** + * Get whether a session exists for the given owner. + * + * @param owner the owner + * @return true if a session exists + */ + public synchronized boolean contains(SessionOwner owner) { + checkNotNull(owner); + return sessions.containsKey(getKey(owner)); + } + + /** + * Find a session by its name specified by {@link SessionKey#getName()}. + * + * @param name the name + * @return the session, if found, otherwise {@code null} + */ + @Nullable + public synchronized LocalSession findByName(String name) { + checkNotNull(name); + for (SessionHolder holder : sessions.values()) { + String test = holder.key.getName(); + if (name.equals(test)) { + return holder.session; + } + } + + return null; + } + + /** + * Gets the session for an owner and return it if it exists, otherwise + * return {@code null}. + * + * @param owner the owner + * @return the session for the owner, if it exists + */ + @Nullable + public synchronized LocalSession getIfPresent(SessionOwner owner) { + checkNotNull(owner); + SessionHolder stored = sessions.get(getKey(owner)); + if (stored != null) { + if (stored.sessionIdle && stored.key.isActive()) { + stored.sessionIdle = false; + } + return stored.session; + } else { + return null; + } + } + + /** + * Get the session for an owner and create one if one doesn't exist. + * + * @param owner the owner + * @return a session + */ + public synchronized LocalSession get(SessionOwner owner) { + checkNotNull(owner); + + LocalSession session = getIfPresent(owner); + LocalConfiguration config = worldEdit.getConfiguration(); + SessionKey sessionKey = owner.getSessionKey(); + + // No session exists yet -- create one + if (session == null) { + try { + session = store.load(getKey(sessionKey)); + session.postLoad(); + } catch (IOException e) { + LOGGER.warn("Failed to load saved session", e); + session = new LocalSession(); + } + Request.request().setSession(session); + + session.setConfiguration(config); + session.setBlockChangeLimit(config.defaultChangeLimit); + session.setTimeout(config.calculationTimeout); + try { + String sessionItem = session.isWandItemDefault() ? null : session.getWandItem(); + setDefaultWand(sessionItem, config.wandItem, session, new SelectionWand()); + } catch (InvalidToolBindException e) { + if (warnedInvalidTool.add("selwand")) { + LOGGER.warn("Invalid selection wand tool set in config. Tool will not be assigned: " + e.getItemType()); + } + } + try { + String sessionItem = session.isNavWandItemDefault() ? null : session.getNavWandItem(); + setDefaultWand(sessionItem, config.navigationWand, session, new NavigationWand()); + } catch (InvalidToolBindException e) { + if (warnedInvalidTool.add("navwand")) { + LOGGER.warn("Invalid navigation wand tool set in config. Tool will not be assigned: " + e.getItemType()); + } + } + session.compareAndResetDirty(); + + // Remember the session regardless of if it's currently active or not. + // And have the SessionTracker FLUSH inactive sessions. + sessions.put(getKey(owner), new SessionHolder(sessionKey, session)); + } + + if (shouldBoundLimit(owner, "worldedit.limit.unrestricted", session.getBlockChangeLimit(), config.maxChangeLimit)) { + session.setBlockChangeLimit(config.maxChangeLimit); + } + if (shouldBoundLimit(owner, "worldedit.timeout.unrestricted", session.getTimeout(), config.maxCalculationTimeout)) { + session.setTimeout(config.maxCalculationTimeout); + } + + // Have the session use inventory if it's enabled and the owner + // doesn't have an override + session.setUseInventory(config.useInventory + && !(config.useInventoryOverride + && (owner.hasPermission("worldedit.inventory.unrestricted") + || (config.useInventoryCreativeOverride && (!(owner instanceof Player) || ((Player) owner).getGameMode() == GameModes.CREATIVE))))); + + // Force non-locatable actors to use placeAtPos1 + if (!(owner instanceof Locatable)) { + session.setPlaceAtPos1(true); + } + + return session; + } + + private boolean shouldBoundLimit(SessionOwner owner, String permission, int currentLimit, int maxLimit) { + if (maxLimit > -1) { // if max is finite + return (currentLimit < 0 || currentLimit > maxLimit) // make sure current is finite and less than max + && !owner.hasPermission(permission); // unless user has unlimited permission + } + return false; + } + + private void setDefaultWand(String sessionItem, String configItem, LocalSession session, Tool wand) throws InvalidToolBindException { + ItemType wandItem = null; + if (sessionItem != null) { + wandItem = ItemTypes.get(sessionItem); + } + if (wandItem == null) { + wandItem = ItemTypes.get(configItem); + } + if (wandItem != null) { + session.setTool(wandItem, wand); + } + } + + /** + * Save a map of sessions to disk. + * + * @param sessions a map of sessions to save + * @return a future that completes on save or error + */ + private ListenableFuture commit(final Map sessions) { + checkNotNull(sessions); + + if (sessions.isEmpty()) { + return Futures.immediateFuture(sessions); + } + + return executorService.submit((Callable) () -> { + Exception exception = null; + + for (Map.Entry entry : sessions.entrySet()) { + SessionKey key = entry.getKey(); + + if (key.isPersistent()) { + try { + store.save(getKey(key), entry.getValue()); + } catch (IOException e) { + LOGGER.warn("Failed to write session for UUID " + getKey(key), e); + exception = e; + } + } + } + + if (exception != null) { + throw exception; + } + + return sessions; + }); + } + + /** + * Get the key to use in the map for an owner. + * + * @param owner the owner + * @return the key object + */ + protected UUID getKey(SessionOwner owner) { + return getKey(owner.getSessionKey()); + } + + + /** + * Get the key to use in the map for a {@code SessionKey}. + * + * @param key the session key object + * @return the key object + */ + protected UUID getKey(SessionKey key) { + return key.getUniqueId(); + } + + /** + * Remove the session for the given owner if one exists. + * + * @param owner the owner + */ + public synchronized void remove(SessionOwner owner) { + checkNotNull(owner); + sessions.remove(getKey(owner)); + } + + /** + * Called to unload this session manager. + */ + public synchronized void unload() { + clear(); + timer.cancel(); + } + + /** + * Remove all sessions. + */ + public synchronized void clear() { + saveChangedSessions(); + sessions.clear(); + } + + private synchronized void saveChangedSessions() { + long now = System.currentTimeMillis(); + Iterator it = sessions.values().iterator(); + Map saveQueue = new HashMap<>(); + + while (it.hasNext()) { + SessionHolder stored = it.next(); + if (stored.key.isActive()) { + stored.lastActive = now; + + if (stored.session.compareAndResetDirty()) { + saveQueue.put(stored.key, stored.session); + } + } else { + if (now - stored.lastActive > EXPIRATION_GRACE) { + if (stored.session.compareAndResetDirty()) { + saveQueue.put(stored.key, stored.session); + } + + it.remove(); + } + } + } + + if (!saveQueue.isEmpty()) { + commit(saveQueue); + } + } + + @Subscribe + public void onConfigurationLoad(ConfigurationLoadEvent event) { + LocalConfiguration config = event.getConfiguration(); + File dir = new File(config.getWorkingDirectory(), "sessions"); + store = new JsonFileSessionStore(dir); + } + + @Subscribe + public void onSessionIdle(final SessionIdleEvent event) { + SessionHolder holder = this.sessions.get(getKey(event.getKey())); + if (holder != null && !holder.sessionIdle) { + holder.sessionIdle = true; + LocalSession session = holder.session; + + // Perform any session cleanup for data that should not be persisted. + session.onIdle(); + } + } + + /** + * Stores the owner of a session, the session, and the last active time. + */ + private static final class SessionHolder { + private final SessionKey key; + private final LocalSession session; + private long lastActive = System.currentTimeMillis(); + private boolean sessionIdle = false; + + private SessionHolder(SessionKey key, LocalSession session) { + this.key = key; + this.session = session; + } + } + + /** + * Removes inactive sessions after they have been inactive for a period + * of time. Commits them as well. + */ + private class SessionTracker extends TimerTask { + @Override + public void run() { + synchronized (SessionManager.this) { + saveChangedSessions(); + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/session/SessionOwner.java b/src/main/java/com/sk89q/worldedit/session/SessionOwner.java new file mode 100644 index 0000000..022b281 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/SessionOwner.java @@ -0,0 +1,36 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session; + +import com.sk89q.worldedit.util.auth.Subject; + +/** + * An object that owns a session. + */ +public interface SessionOwner extends Subject { + + /** + * Get an object describing this session. + * + * @return the status object + */ + SessionKey getSessionKey(); + +} diff --git a/src/main/java/com/sk89q/worldedit/session/TransientSessionException.java b/src/main/java/com/sk89q/worldedit/session/TransientSessionException.java new file mode 100644 index 0000000..d25d4e9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/TransientSessionException.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session; + +/** + * Thrown if the session cannot be persisted + * (because {@link SessionKey#isPersistent()} returns false). + */ +public class TransientSessionException extends Exception { + + public TransientSessionException() { + } + + public TransientSessionException(String message) { + super(message); + } + + public TransientSessionException(String message, Throwable cause) { + super(message, cause); + } + + public TransientSessionException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/sk89q/worldedit/session/request/Request.java b/src/main/java/com/sk89q/worldedit/session/request/Request.java new file mode 100644 index 0000000..cb1d506 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/request/Request.java @@ -0,0 +1,126 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session.request; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; + +/** + * Describes the current request using a {@link ThreadLocal}. + */ +public final class Request { + + private static final ThreadLocal threadLocal = ThreadLocal.withInitial(Request::new); + + private @Nullable World world; + private @Nullable LocalSession session; + private @Nullable EditSession editSession; + private boolean valid; + + private Request() { + } + + /** + * Get the request world. + * + * @return the world, which may be null + */ + public @Nullable World getWorld() { + return world; + } + + /** + * Set the request world. + * + * @param world the world, which may be null + */ + public void setWorld(@Nullable World world) { + this.world = world; + } + + /** + * Get the request session. + * + * @return the session, which may be null + */ + public @Nullable LocalSession getSession() { + return session; + } + + /** + * Get the request session. + * + * @param session the session, which may be null + */ + public void setSession(@Nullable LocalSession session) { + this.session = session; + } + + /** + * Get the {@link EditSession}. + * + * @return the edit session, which may be null + */ + public @Nullable EditSession getEditSession() { + return editSession; + } + + /** + * Set the {@link EditSession}. + * + * @param editSession the edit session, which may be null + */ + public void setEditSession(@Nullable EditSession editSession) { + this.editSession = editSession; + } + + /** + * Get the current request, which is specific to the current thread. + * + * @return the current request + */ + public static Request request() { + return threadLocal.get(); + } + + /** + * Reset the current request and clear all fields. + */ + public static void reset() { + request().invalidate(); + threadLocal.remove(); + } + + /** + * Check if the current request object is still valid. Invalid requests may contain outdated values. + * + * @return true if the request is valid + */ + public boolean isValid() { + return valid; + } + + private void invalidate() { + valid = false; + } +} diff --git a/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java b/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java new file mode 100644 index 0000000..5d835e3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java @@ -0,0 +1,114 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session.request; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.List; +import javax.annotation.Nullable; + +public class RequestExtent implements Extent { + + private Request request; + + protected Extent getExtent() { + if (request == null || !request.isValid()) { + request = Request.request(); + } + final EditSession editSession = request.getEditSession(); + return editSession == null ? request.getWorld() : editSession; + } + + @Override + public BlockVector3 getMinimumPoint() { + return getExtent().getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return getExtent().getMaximumPoint(); + } + + @Override + public List getEntities(Region region) { + return getExtent().getEntities(region); + } + + @Override + public List getEntities() { + return getExtent().getEntities(); + } + + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity) { + return getExtent().createEntity(location, entity); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return getExtent().getBlock(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return getExtent().getFullBlock(position); + } + + @Override + public BiomeType getBiome(BlockVector3 position) { + return getExtent().getBiome(position); + } + + @Override + public > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return getExtent().setBlock(position, block); + } + + @Override + public boolean fullySupports3DBiomes() { + return getExtent().fullySupports3DBiomes(); + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + return getExtent().setBiome(position, biome); + } + + @Override + @Nullable + public Operation commit() { + Operation commit = getExtent().commit(); + request = null; + return commit; + } +} diff --git a/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java b/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java new file mode 100644 index 0000000..7028513 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java @@ -0,0 +1,155 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session.request; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.NullRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.world.World; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * A region that mirrors the current selection according to the current + * {@link LocalSession} and {@link World} set on the current + * {@link Request}. + * + *

If a selection cannot be taken, then the selection will be assumed to be + * that of a {@link NullRegion}.

+ */ +public class RequestSelection implements Region { + + /** + * Get the delegate region. + * + * @return the delegate region + */ + protected Region getRegion() { + LocalSession session = Request.request().getSession(); + World world = Request.request().getWorld(); + + if (session != null && world != null) { + try { + return session.getSelection(world); + } catch (IncompleteRegionException ignored) { + } + } + + return new NullRegion(); + } + + @Override + public BlockVector3 getMinimumPoint() { + return getRegion().getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return getRegion().getMaximumPoint(); + } + + @Override + public Vector3 getCenter() { + return getRegion().getCenter(); + } + + @Override + public long getVolume() { + return getRegion().getVolume(); + } + + @Override + public int getWidth() { + return getRegion().getWidth(); + } + + @Override + public int getHeight() { + return getRegion().getHeight(); + } + + @Override + public int getLength() { + return getRegion().getLength(); + } + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + getRegion().expand(changes); + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + getRegion().contract(changes); + } + + @Override + public void shift(BlockVector3 change) throws RegionOperationException { + getRegion().shift(change); + } + + @Override + public boolean contains(BlockVector3 position) { + return getRegion().contains(position); + } + + @Override + public Set getChunks() { + return getRegion().getChunks(); + } + + @Override + public Set getChunkCubes() { + return getRegion().getChunkCubes(); + } + + @Override + public World getWorld() { + return getRegion().getWorld(); + } + + @Override + public void setWorld(World world) { + getRegion().setWorld(world); + } + + @Override + public Region clone() { + return this; + } + + @Override + public List polygonize(int maxPoints) { + return getRegion().polygonize(maxPoints); + } + + @Override + public Iterator iterator() { + return getRegion().iterator(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/session/storage/JsonFileSessionStore.java b/src/main/java/com/sk89q/worldedit/session/storage/JsonFileSessionStore.java new file mode 100644 index 0000000..dfc9a5d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/storage/JsonFileSessionStore.java @@ -0,0 +1,130 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session.storage; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonIOException; +import com.google.gson.JsonParseException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.util.gson.GsonUtil; +import com.sk89q.worldedit.util.io.Closer; +import org.apache.logging.log4j.Logger; + +import java.io.*; +import java.util.UUID; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Stores sessions as JSON files in a directory. + * + *

Currently, this implementation doesn't handle thread safety very well.

+ */ +public class JsonFileSessionStore implements SessionStore { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private final Gson gson; + private final File dir; + + /** + * Create a new session store. + * + * @param dir the directory + */ + public JsonFileSessionStore(File dir) { + checkNotNull(dir); + + if (!dir.isDirectory()) { + if (!dir.mkdirs()) { + LOGGER.warn("Failed to create directory '" + dir.getPath() + "' for sessions"); + } + } + + this.dir = dir; + + GsonBuilder builder = GsonUtil.createBuilder(); + gson = builder.create(); + } + + /** + * Get the path for the given UUID. + * + * @param id the ID + * @return the file + */ + private File getPath(UUID id) { + checkNotNull(id); + return new File(dir, id + ".json"); + } + + @Override + public LocalSession load(UUID id) throws IOException { + File file = getPath(id); + try (Closer closer = Closer.create()) { + FileReader fr = closer.register(new FileReader(file)); + BufferedReader br = closer.register(new BufferedReader(fr)); + LocalSession session = gson.fromJson(br, LocalSession.class); + if (session == null) { + LOGGER.warn("Loaded a null session from {}, creating new session", file); + if (!file.delete()) { + LOGGER.warn("Failed to delete corrupted session {}", file); + } + session = new LocalSession(); + } + return session; + } catch (JsonParseException e) { + throw new IOException(e); + } catch (FileNotFoundException e) { + return new LocalSession(); + } + } + + @Override + public void save(UUID id, LocalSession session) throws IOException { + checkNotNull(session); + File finalFile = getPath(id); + File tempFile = new File(finalFile.getParentFile(), finalFile.getName() + ".tmp"); + + try (Closer closer = Closer.create()) { + FileWriter fr = closer.register(new FileWriter(tempFile)); + BufferedWriter bw = closer.register(new BufferedWriter(fr)); + gson.toJson(session, bw); + } catch (JsonIOException e) { + throw new IOException(e); + } + + if (finalFile.exists()) { + if (!finalFile.delete()) { + LOGGER.warn("Failed to delete " + finalFile.getPath() + " so the .tmp file can replace it"); + } + } + + if (tempFile.length() == 0) { + throw new IllegalStateException("Gson wrote zero bytes"); + } + + if (!tempFile.renameTo(finalFile)) { + LOGGER.warn("Failed to rename temporary session file to " + finalFile.getPath()); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/session/storage/SessionStore.java b/src/main/java/com/sk89q/worldedit/session/storage/SessionStore.java new file mode 100644 index 0000000..a5e578d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/storage/SessionStore.java @@ -0,0 +1,57 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session.storage; + +import com.sk89q.worldedit.LocalSession; + +import java.io.IOException; +import java.util.UUID; + +/** + * Commits sessions to disk. + * + *

Both {@link #load(UUID)} and {@link #save(UUID, LocalSession)} may be + * called at the same in different threads, so implementations should + * be aware of this issue.

+ */ +public interface SessionStore { + + /** + * Load a session identified by the given UUID. + * + *

If the session does not exist (has never been saved), then + * a new {@link LocalSession} must be returned.

+ * + * @param id the UUID + * @return a session + * @throws IOException thrown on read error + */ + LocalSession load(UUID id) throws IOException; + + /** + * Save the given session identified by the given UUID. + * + * @param id the UUID + * @param session a session + * @throws IOException thrown on read error + */ + void save(UUID id, LocalSession session) throws IOException; + +} diff --git a/src/main/java/com/sk89q/worldedit/session/storage/VoidStore.java b/src/main/java/com/sk89q/worldedit/session/storage/VoidStore.java new file mode 100644 index 0000000..712ddfe --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/storage/VoidStore.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.session.storage; + +import com.sk89q.worldedit.LocalSession; + +import java.io.IOException; +import java.util.UUID; + +/** + * A session store that doesn't know how to store sessions. + */ +public class VoidStore implements SessionStore { + + @Override + public LocalSession load(UUID id) throws IOException { + return new LocalSession(); + } + + @Override + public void save(UUID id, LocalSession session) throws IOException { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/Countable.java b/src/main/java/com/sk89q/worldedit/util/Countable.java new file mode 100644 index 0000000..03dfdf6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/Countable.java @@ -0,0 +1,72 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +public class Countable implements Comparable> { + + private T id; + private int amount; + + /** + * Construct the object. + * + * @param id the ID + * @param amount the count of + */ + public Countable(T id, int amount) { + this.id = id; + this.amount = amount; + } + + public T getID() { + return id; + } + + public void setID(T id) { + this.id = id; + } + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } + + /** + * Decrement the amount. + */ + public void decrement() { + --this.amount; + } + + /** + * Increment the amount. + */ + public void increment() { + ++this.amount; + } + + @Override + public int compareTo(Countable other) { + return Integer.compare(amount, other.amount); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/Direction.java b/src/main/java/com/sk89q/worldedit/util/Direction.java new file mode 100644 index 0000000..1a0ac72 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/Direction.java @@ -0,0 +1,280 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; + +/** + * A collection of cardinal, ordinal, and secondary-ordinal directions. + */ +public enum Direction { + + NORTH(Vector3.at(0, 0, -1), Flag.CARDINAL), + EAST(Vector3.at(1, 0, 0), Flag.CARDINAL), + SOUTH(Vector3.at(0, 0, 1), Flag.CARDINAL), + WEST(Vector3.at(-1, 0, 0), Flag.CARDINAL), + + UP(Vector3.at(0, 1, 0), Flag.UPRIGHT), + DOWN(Vector3.at(0, -1, 0), Flag.UPRIGHT), + + NORTHEAST(Vector3.at(1, 0, -1), Flag.ORDINAL), + NORTHWEST(Vector3.at(-1, 0, -1), Flag.ORDINAL), + SOUTHEAST(Vector3.at(1, 0, 1), Flag.ORDINAL), + SOUTHWEST(Vector3.at(-1, 0, 1), Flag.ORDINAL), + + WEST_NORTHWEST(Vector3.at(-Math.cos(Math.PI / 8), 0, -Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + WEST_SOUTHWEST(Vector3.at(-Math.cos(Math.PI / 8), 0, Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + NORTH_NORTHWEST(Vector3.at(-Math.sin(Math.PI / 8), 0, -Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + NORTH_NORTHEAST(Vector3.at(Math.sin(Math.PI / 8), 0, -Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + EAST_NORTHEAST(Vector3.at(Math.cos(Math.PI / 8), 0, -Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + EAST_SOUTHEAST(Vector3.at(Math.cos(Math.PI / 8), 0, Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + SOUTH_SOUTHEAST(Vector3.at(Math.sin(Math.PI / 8), 0, Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL), + SOUTH_SOUTHWEST(Vector3.at(-Math.sin(Math.PI / 8), 0, Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL); + + private final Vector3 direction; + private final int flags; + private final BlockVector3 blockPoint; + + Direction(Vector3 vector, int flags) { + this.blockPoint = vector.toBlockPoint(); + this.direction = vector.normalize(); + this.flags = flags; + } + + /** + * Return true if the direction is of a cardinal direction (north, west + * east, and south). + * + *

This evaluates as false for directions that have a non-zero + * Y-component.

+ * + * @return true if cardinal + */ + public boolean isCardinal() { + return (flags & Flag.CARDINAL) > 0; + } + + /** + * Return true if the direction is of an ordinal direction (northwest, + * southwest, southeast, northeaast). + * + * @return true if ordinal + */ + public boolean isOrdinal() { + return (flags & Flag.ORDINAL) > 0; + } + + /** + * Return true if the direction is of a secondary ordinal direction + * (north-northwest, north-northeast, south-southwest, etc.). + * + * @return true if secondary ordinal + */ + public boolean isSecondaryOrdinal() { + return (flags & Flag.SECONDARY_ORDINAL) > 0; + } + + /** + * Return whether Y component is non-zero. + * + * @return true if the Y component is non-zero + */ + public boolean isUpright() { + return (flags & Flag.UPRIGHT) > 0; + } + + /** + * Get the vector. + * + * @return the vector + */ + public Vector3 toVector() { + return direction; + } + + /** + * Get the vector. + * + * @return the vector + */ + public BlockVector3 toBlockVector() { + return blockPoint; + } + + /** + * Find the closest direction to the given direction vector. + * + * @param vector the vector + * @param flags the only flags that are permitted (use bitwise math) + * @return the closest direction, or null if no direction can be returned + */ + @Nullable + public static Direction findClosest(Vector3 vector, int flags) { + if ((flags & Flag.UPRIGHT) == 0) { + vector = vector.withY(0); + } + vector = vector.normalize(); + + Direction closest = null; + double closestDot = -2; + for (Direction direction : values()) { + if ((~flags & direction.flags) > 0) { + continue; + } + + double dot = direction.toVector().dot(vector); + if (dot >= closestDot) { + closest = direction; + closestDot = dot; + } + } + + return closest; + } + + /** + * Gets all directions with the given flags. + * + * @param flags The flags + * @return The directions that fit the flags + */ + public static List valuesOf(int flags) { + List directions = new ArrayList<>(); + for (Direction direction : values()) { + if ((~flags & direction.flags) == 0) { + directions.add(direction); + } + } + + return directions; + } + + /** + * Converts a rotation index into a Direction. + * + *

+ * Rotation indexes are used in BlockStates, such as sign posts. + *

+ * + * @param rotation The rotation index + * @return The direction, if applicable + */ + public static Optional fromRotationIndex(int rotation) { + switch (rotation) { + case 0: + return Optional.of(SOUTH); + case 1: + return Optional.of(SOUTH_SOUTHWEST); + case 2: + return Optional.of(SOUTHWEST); + case 3: + return Optional.of(WEST_SOUTHWEST); + case 4: + return Optional.of(WEST); + case 5: + return Optional.of(WEST_NORTHWEST); + case 6: + return Optional.of(NORTHWEST); + case 7: + return Optional.of(NORTH_NORTHWEST); + case 8: + return Optional.of(NORTH); + case 9: + return Optional.of(NORTH_NORTHEAST); + case 10: + return Optional.of(NORTHEAST); + case 11: + return Optional.of(EAST_NORTHEAST); + case 12: + return Optional.of(EAST); + case 13: + return Optional.of(EAST_SOUTHEAST); + case 14: + return Optional.of(SOUTHEAST); + case 15: + return Optional.of(SOUTH_SOUTHEAST); + default: + return Optional.empty(); + } + } + + public OptionalInt toRotationIndex() { + switch (this) { + case SOUTH: + return OptionalInt.of(0); + case SOUTH_SOUTHWEST: + return OptionalInt.of(1); + case SOUTHWEST: + return OptionalInt.of(2); + case WEST_SOUTHWEST: + return OptionalInt.of(3); + case WEST: + return OptionalInt.of(4); + case WEST_NORTHWEST: + return OptionalInt.of(5); + case NORTHWEST: + return OptionalInt.of(6); + case NORTH_NORTHWEST: + return OptionalInt.of(7); + case NORTH: + return OptionalInt.of(8); + case NORTH_NORTHEAST: + return OptionalInt.of(9); + case NORTHEAST: + return OptionalInt.of(10); + case EAST_NORTHEAST: + return OptionalInt.of(11); + case EAST: + return OptionalInt.of(12); + case EAST_SOUTHEAST: + return OptionalInt.of(13); + case SOUTHEAST: + return OptionalInt.of(14); + case SOUTH_SOUTHEAST: + return OptionalInt.of(15); + default: + return OptionalInt.empty(); + } + } + + /** + * Flags to use with {@link #findClosest(Vector3, int)}. + */ + public static final class Flag { + public static int CARDINAL = 0x1; + public static int ORDINAL = 0x2; + public static int SECONDARY_ORDINAL = 0x4; + public static int UPRIGHT = 0x8; + + public static int ALL = CARDINAL | ORDINAL | SECONDARY_ORDINAL | UPRIGHT; + + private Flag() { + } + } + +} + diff --git a/src/main/java/com/sk89q/worldedit/util/Enums.java b/src/main/java/com/sk89q/worldedit/util/Enums.java new file mode 100644 index 0000000..5669bb9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/Enums.java @@ -0,0 +1,55 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helper methods for enums. + */ +public final class Enums { + + private Enums() { + } + + /** + * Search the given enum for a value that is equal to the one of the + * given values, searching in an ascending manner. + * + * @param enumType the enum type + * @param values the list of values + * @param the type of enum + * @return the found value or null + */ + @Nullable + public static > T findByValue(Class enumType, String... values) { + checkNotNull(enumType); + checkNotNull(values); + for (String val : values) { + try { + return Enum.valueOf(enumType, val); + } catch (IllegalArgumentException ignored) { + } + } + return null; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/Faceted.java b/src/main/java/com/sk89q/worldedit/util/Faceted.java new file mode 100644 index 0000000..74b5ccc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/Faceted.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import com.sk89q.worldedit.entity.Entity; + +import javax.annotation.Nullable; + +/** + * Indicates that an object can provide various "facets," which are + * specific distinct interfaces that can represent a portion of the object. + * + *

For example, an instance of an {@link Entity} may have a facet + * for accessing its inventory (if it contains an inventory) or a facet + * for accessing its health (if it has health).

+ * + *

Facets are referred to by their interface or abstract class and + * it is dependent on the implementation of the object specifying this + * interface to return the most applicable implementation. However, in + * many cases, such an implementation may not apply or it has not been + * implemented so a request for a facet may return {@code null}.

+ */ +public interface Faceted { + + /** + * Get the facet corresponding to the given class or interface. + * + * @param cls the class or interface + * @param the type + * @return an implementation of the facet or {@code null} if one is unavailable + */ + @Nullable + T getFacet(Class cls); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/FileDialogUtil.java b/src/main/java/com/sk89q/worldedit/util/FileDialogUtil.java new file mode 100644 index 0000000..9fe8f84 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/FileDialogUtil.java @@ -0,0 +1,96 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import com.sk89q.util.StringUtil; + +import javax.swing.*; +import javax.swing.filechooser.FileFilter; +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public final class FileDialogUtil { + private FileDialogUtil() { + } + + public static File showSaveDialog(String[] exts) { + JFileChooser dialog = new JFileChooser(); + + if (exts != null) { + dialog.setFileFilter(new ExtensionFilter(exts)); + } + + int returnVal = dialog.showSaveDialog(null); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + return dialog.getSelectedFile(); + } + + return null; + } + + public static File showOpenDialog(String[] exts) { + JFileChooser dialog = new JFileChooser(); + + if (exts != null) { + dialog.setFileFilter(new ExtensionFilter(exts)); + } + + int returnVal = dialog.showOpenDialog(null); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + return dialog.getSelectedFile(); + } + + return null; + } + + private static class ExtensionFilter extends FileFilter { + private final Set exts; + private final String desc; + + private ExtensionFilter(String[] exts) { + this.exts = new HashSet<>(Arrays.asList(exts)); + + desc = StringUtil.joinString(exts, ","); + } + + @Override + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + String path = f.getPath(); + int index = path.lastIndexOf('.'); + if (index == -1 || index == path.length() - 1) { + return false; + } else { + return exts.contains(path.substring(index + 1)); + } + } + + @Override + public String getDescription() { + return desc; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/GuavaUtil.java b/src/main/java/com/sk89q/worldedit/util/GuavaUtil.java new file mode 100644 index 0000000..b35d01c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/GuavaUtil.java @@ -0,0 +1,34 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class GuavaUtil { + + private GuavaUtil() { + } + + public static T firstNonNull(@Nullable T first, @Nullable T second) { + return first != null ? first : checkNotNull(second); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/HandSide.java b/src/main/java/com/sk89q/worldedit/util/HandSide.java new file mode 100644 index 0000000..e7632bd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/HandSide.java @@ -0,0 +1,25 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +public enum HandSide { + MAIN_HAND, + OFF_HAND +} diff --git a/src/main/java/com/sk89q/worldedit/util/Identifiable.java b/src/main/java/com/sk89q/worldedit/util/Identifiable.java new file mode 100644 index 0000000..88b8018 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/Identifiable.java @@ -0,0 +1,36 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import java.util.UUID; + +/** + * Represents an object that can be identified by a UUID. + */ +public interface Identifiable { + + /** + * Get the UUID for this object. + * + * @return the UUID + */ + UUID getUniqueId(); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java b/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java new file mode 100644 index 0000000..2ea1d1d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a block located at some position. + */ +public final class LocatedBlock { + + private final BlockVector3 location; + private final BaseBlock block; + + public LocatedBlock(BlockVector3 location, BaseBlock block) { + this.location = checkNotNull(location); + this.block = checkNotNull(block); + } + + public BlockVector3 getLocation() { + return location; + } + + public BaseBlock getBlock() { + return block; + } + + @Override + public int hashCode() { + return Objects.hash(location, block); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (this.getClass() != obj.getClass()) { + return false; + } + LocatedBlock lb = (LocatedBlock) obj; + return Objects.equals(location, lb.location) && Objects.equals(block, lb.block); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/Location.java b/src/main/java/com/sk89q/worldedit/util/Location.java new file mode 100644 index 0000000..46b8c50 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/Location.java @@ -0,0 +1,384 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.Vector3; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a location in a world with has a direction. + * + *

Like {@code Vectors}, {@code Locations} are immutable and mutator methods + * will create a new copy.

+ * + *

At the moment, but this may change in the future, {@link #hashCode()} and + * {@link #equals(Object)} are subject to minor differences caused by + * floating point errors.

+ */ +public class Location { + + private final Extent extent; + private final Vector3 position; + private final float pitch; + private final float yaw; + + /** + * Create a new instance in the given extent at 0, 0, 0 with a + * direction vector of 0, 0, 0. + * + * @param extent the extent + */ + public Location(Extent extent) { + this(extent, Vector3.ZERO, 0f, 90f); + } + + /** + * Create a new instance in the given extent with the given coordinates + * with a direction vector of 0, 0, 0. + * + * @param extent the extent + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + */ + public Location(Extent extent, double x, double y, double z) { + this(extent, Vector3.at(x, y, z), 0f, 90f); + } + + /** + * Create a new instance in the given extent with the given position + * vector and a direction vector of 0, 0, 0. + * + * @param extent the extent + * @param position the position vector + */ + public Location(Extent extent, Vector3 position) { + this(extent, position, 0f, 90f); + } + + /** + * Create a new instance in the given extent with the given coordinates + * and the given direction vector. + * + * @param extent the extent + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + * @param direction the direction vector + */ + public Location(Extent extent, double x, double y, double z, Vector3 direction) { + this(extent, Vector3.at(x, y, z), direction); + } + + /** + * Create a new instance in the given extent with the given coordinates + * and the given direction vector. + * + * @param extent the extent + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + * @param yaw the yaw, in degrees + * @param pitch the pitch, in degrees + */ + public Location(Extent extent, double x, double y, double z, float yaw, float pitch) { + this(extent, Vector3.at(x, y, z), yaw, pitch); + } + + /** + * Create a new instance in the given extent with the given position vector + * and the given direction vector. + * + * @param extent the extent + * @param position the position vector + * @param direction the direction vector + */ + public Location(Extent extent, Vector3 position, Vector3 direction) { + this(extent, position, (float) direction.toYaw(), (float) direction.toPitch()); + } + + /** + * Create a new instance in the given extent with the given position vector + * and the given direction vector. + * + * @param extent the extent + * @param position the position vector + * @param yaw the yaw, in degrees + * @param pitch the pitch, in degrees + */ + public Location(Extent extent, Vector3 position, float yaw, float pitch) { + checkNotNull(extent); + checkNotNull(position); + this.extent = extent; + this.position = position; + this.pitch = pitch; + this.yaw = yaw; + } + + /** + * Get the extent. + * + * @return the extent + */ + public Extent getExtent() { + return extent; + } + + /** + * Create a clone of this object with the given extent. + * + * @param extent the new extent + * @return the new instance + */ + public Location setExtent(Extent extent) { + return new Location(extent, position, getDirection()); + } + + /** + * Get the yaw in degrees. + * + * @return the yaw in degrees + */ + public float getYaw() { + return yaw; + } + + /** + * Create a clone of this object with the given yaw. + * + * @param yaw the new yaw + * @return the new instance + */ + public Location setYaw(float yaw) { + return new Location(extent, position, yaw, pitch); + } + + /** + * Get the pitch in degrees. + * + * @return the pitch in degrees + */ + public float getPitch() { + return pitch; + } + + /** + * Create a clone of this object with the given pitch. + * + * @param pitch the new yaw + * @return the new instance + */ + public Location setPitch(float pitch) { + return new Location(extent, position, yaw, pitch); + } + + /** + * Create a clone of this object with the given yaw and pitch. + * + * @param yaw the new yaw + * @param pitch the new pitch + * @return the new instance + */ + public Location setDirection(float yaw, float pitch) { + return new Location(extent, position, yaw, pitch); + } + + /** + * Get the direction vector. + * + * @return the direction vector + */ + public Vector3 getDirection() { + if (Float.isNaN(getYaw()) && Float.isNaN(getPitch())) { + return Vector3.ZERO; + } + double yaw = Math.toRadians(this.getYaw()); + double pitch = Math.toRadians(this.getPitch()); + double xz = Math.cos(pitch); + return Vector3.at( + -xz * Math.sin(yaw), + -Math.sin(pitch), + xz * Math.cos(yaw)); + } + + /** + * Get the direction as a {@link Direction}. + * + * @return The direction + */ + public Direction getDirectionEnum() { + return Direction.findClosest(getDirection(), Direction.Flag.ALL); + } + + /** + * Create a clone of this object with the given direction. + * + * @param direction the new direction + * @return the new instance + */ + public Location setDirection(Vector3 direction) { + return new Location(extent, position, (float) direction.toYaw(), (float) direction.toPitch()); + } + + /** + * Get a {@link Vector3} form of this location's position. + * + * @return a vector + */ + public Vector3 toVector() { + return position; + } + + /** + * Get the X component of the position vector. + * + * @return the X component + */ + public double getX() { + return position.getX(); + } + + /** + * Get the rounded X component of the position vector. + * + * @return the rounded X component + */ + public int getBlockX() { + return (int) Math.floor(position.getX()); + } + + /** + * Return a copy of this object with the X component of the new object + * set to the given value. + * + * @param x the new value for the X component + * @return a new immutable instance + */ + public Location setX(double x) { + return new Location(extent, position.withX(x), yaw, pitch); + } + + /** + * Get the Y component of the position vector. + * + * @return the Y component + */ + public double getY() { + return position.getY(); + } + + /** + * Get the rounded Y component of the position vector. + * + * @return the rounded Y component + */ + public int getBlockY() { + return (int) Math.floor(position.getY()); + } + + /** + * Return a copy of this object with the Y component of the new object + * set to the given value. + * + * @param y the new value for the Y component + * @return a new immutable instance + */ + public Location setY(double y) { + return new Location(extent, position.withY(y), yaw, pitch); + } + + /** + * Get the Z component of the position vector. + * + * @return the Z component + */ + public double getZ() { + return position.getZ(); + } + + /** + * Get the rounded Z component of the position vector. + * + * @return the rounded Z component + */ + public int getBlockZ() { + return (int) Math.floor(position.getZ()); + } + + /** + * Return a copy of this object with the Z component of the new object + * set to the given value. + * + * @param z the new value for the Y component + * @return a new immutable instance + */ + public Location setZ(double z) { + return new Location(extent, position.withZ(z), yaw, pitch); + } + + /** + * Return a copy of this object with the position set to the given value. + * + * @param position The new position + * @return a new immutable instance + */ + public Location setPosition(Vector3 position) { + return new Location(extent, position, yaw, pitch); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Location location = (Location) o; + + if (Double.doubleToLongBits(pitch) != Double.doubleToLongBits(location.pitch)) { + return false; + } + if (Double.doubleToLongBits(yaw) != Double.doubleToLongBits(location.yaw)) { + return false; + } + if (!position.equals(location.position)) { + return false; + } + if (!extent.equals(location.extent)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = extent.hashCode(); + result = 31 * result + position.hashCode(); + result = 31 * result + Float.floatToIntBits(this.pitch); + result = 31 * result + Float.floatToIntBits(this.yaw); + return result; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java new file mode 100644 index 0000000..8dd5ef1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -0,0 +1,286 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.util; + +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.util.report.Unreported; +import com.sk89q.worldedit.world.registry.LegacyMapper; +import org.apache.logging.log4j.Logger; + +import java.io.*; +import java.nio.file.Path; +import java.util.*; + +/** + * Simple LocalConfiguration that loads settings using + * {@code java.util.Properties}. + */ +public class PropertiesConfiguration extends LocalConfiguration { + + @Unreported private static final Logger LOGGER = LogManagerCompat.getLogger(); + + @Unreported protected Properties properties; + @Unreported protected File path; + + /** + * Construct the object. The configuration isn't loaded yet. + * + * @param path the path to the configuration + */ + public PropertiesConfiguration(Path path) { + this.path = path.toFile(); + + properties = new Properties(); + } + + /** + * Construct the object. The configuration isn't loaded yet. + * + * @param path the path to the configuration + * @deprecated Use {@link PropertiesConfiguration#PropertiesConfiguration(Path)} + */ + @Deprecated + public PropertiesConfiguration(File path) { + this(path.toPath()); + } + + @Override + public void load() { + try (InputStream stream = new FileInputStream(path)) { + properties.load(stream); + } catch (FileNotFoundException ignored) { + } catch (IOException e) { + LOGGER.warn("Failed to read configuration", e); + } + + loadExtra(); + + profile = getBool("profile", profile); + traceUnflushedSessions = getBool("trace-unflushed-sessions", traceUnflushedSessions); + disallowedBlocks = getStringSet("disallowed-blocks", getDefaultDisallowedBlocks()); + defaultChangeLimit = getInt("default-max-changed-blocks", defaultChangeLimit); + maxChangeLimit = getInt("max-changed-blocks", maxChangeLimit); + defaultVerticalHeight = getInt("default-vertical-height", defaultVerticalHeight); + defaultMaxPolygonalPoints = getInt("default-max-polygon-points", defaultMaxPolygonalPoints); + maxPolygonalPoints = getInt("max-polygon-points", maxPolygonalPoints); + defaultMaxPolyhedronPoints = getInt("default-max-polyhedron-points", defaultMaxPolyhedronPoints); + maxPolyhedronPoints = getInt("max-polyhedron-points", maxPolyhedronPoints); + shellSaveType = getString("shell-save-type", shellSaveType); + maxRadius = getInt("max-radius", maxRadius); + maxSuperPickaxeSize = getInt("max-super-pickaxe-size", maxSuperPickaxeSize); + maxBrushRadius = getInt("max-brush-radius", maxBrushRadius); + logCommands = getBool("log-commands", logCommands); + logFile = getString("log-file", logFile); + logFormat = getString("log-format", logFormat); + registerHelp = getBool("register-help", registerHelp); + wandItem = getString("wand-item", wandItem).toLowerCase(Locale.ROOT); + try { + wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).getId(); + } catch (Throwable ignored) { + } + superPickaxeDrop = getBool("super-pickaxe-drop-items", superPickaxeDrop); + superPickaxeManyDrop = getBool("super-pickaxe-many-drop-items", superPickaxeManyDrop); + useInventory = getBool("use-inventory", useInventory); + useInventoryOverride = getBool("use-inventory-override", useInventoryOverride); + useInventoryCreativeOverride = getBool("use-inventory-creative-override", useInventoryCreativeOverride); + navigationWand = getString("nav-wand-item", navigationWand).toLowerCase(Locale.ROOT); + try { + navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).getId(); + } catch (Throwable ignored) { + } + navigationWandMaxDistance = getInt("nav-wand-distance", navigationWandMaxDistance); + navigationUseGlass = getBool("nav-use-glass", navigationUseGlass); + scriptTimeout = getInt("scripting-timeout", scriptTimeout); + calculationTimeout = getInt("calculation-timeout", calculationTimeout); + maxCalculationTimeout = getInt("max-calculation-timeout", maxCalculationTimeout); + saveDir = getString("schematic-save-dir", saveDir); + scriptsDir = getString("craftscript-dir", scriptsDir); + butcherDefaultRadius = getInt("butcher-default-radius", butcherDefaultRadius); + butcherMaxRadius = getInt("butcher-max-radius", butcherMaxRadius); + allowSymlinks = getBool("allow-symbolic-links", allowSymlinks); + serverSideCUI = getBool("server-side-cui", serverSideCUI); + extendedYLimit = getBool("extended-y-limit", extendedYLimit); + setDefaultLocaleName(getString("default-locale", defaultLocaleName)); + commandBlockSupport = getBool("command-block-support", commandBlockSupport); + + LocalSession.MAX_HISTORY_SIZE = Math.max(15, getInt("history-size", 15)); + + String snapshotsDir = getString("snapshots-dir", ""); + boolean experimentalSnapshots = getBool("snapshots-experimental", false); + initializeSnapshotConfiguration(snapshotsDir, experimentalSnapshots); + + path.getParentFile().mkdirs(); + try (OutputStream output = new FileOutputStream(path)) { + properties.store(output, "Don't put comments; they get removed"); + } catch (IOException e) { + LOGGER.warn("Failed to write configuration", e); + } + } + + /** + * Called to load extra configuration. + */ + protected void loadExtra() { + } + + /** + * Get a string value. + * + * @param key the key + * @param def the default value + * @return the value + */ + protected String getString(String key, String def) { + if (def == null) { + def = ""; + } + String val = properties.getProperty(key); + if (val == null) { + properties.setProperty(key, def); + return def; + } else { + return val; + } + } + + /** + * Get a boolean value. + * + * @param key the key + * @param def the default value + * @return the value + */ + protected boolean getBool(String key, boolean def) { + String val = properties.getProperty(key); + if (val == null) { + properties.setProperty(key, def ? "true" : "false"); + return def; + } else { + return val.equalsIgnoreCase("true") + || val.equals("1"); + } + } + + /** + * Get an integer value. + * + * @param key the key + * @param def the default value + * @return the value + */ + protected int getInt(String key, int def) { + String val = properties.getProperty(key); + if (val == null) { + properties.setProperty(key, String.valueOf(def)); + return def; + } else { + try { + return Integer.parseInt(val); + } catch (NumberFormatException e) { + properties.setProperty(key, String.valueOf(def)); + return def; + } + } + } + + /** + * Get a double value. + * + * @param key the key + * @param def the default value + * @return the value + */ + protected double getDouble(String key, double def) { + String val = properties.getProperty(key); + if (val == null) { + properties.setProperty(key, String.valueOf(def)); + return def; + } else { + try { + return Double.parseDouble(val); + } catch (NumberFormatException e) { + properties.setProperty(key, String.valueOf(def)); + return def; + } + } + } + + /** + * Get a double value. + * + * @param key the key + * @param def the default value + * @return the value + */ + protected Set getIntSet(String key, int[] def) { + String val = properties.getProperty(key); + if (val == null) { + properties.setProperty(key, StringUtil.joinString(def, ",", 0)); + Set set = new HashSet<>(); + for (int i : def) { + set.add(i); + } + return set; + } else { + Set set = new HashSet<>(); + String[] parts = val.split(","); + for (String part : parts) { + try { + int v = Integer.parseInt(part.trim()); + set.add(v); + } catch (NumberFormatException ignored) { + } + } + return set; + } + } + + /** + * Get a String set. + * + * @param key the key + * @param def the default value + * @return the value + */ + protected Set getStringSet(String key, String[] def) { + String val = properties.getProperty(key); + if (val == null) { + properties.setProperty(key, StringUtil.joinString(def, ",", 0)); + return new HashSet<>(Arrays.asList(def)); + } else { + Set set = new HashSet<>(); + String[] parts = val.split(","); + for (String part : parts) { + try { + String v = part.trim(); + set.add(v); + } catch (NumberFormatException ignored) { + } + } + return set; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/SideEffect.java b/src/main/java/com/sk89q/worldedit/util/SideEffect.java new file mode 100644 index 0000000..e2793cd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/SideEffect.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import java.util.Locale; + +public enum SideEffect { + LIGHTING(State.ON), + NEIGHBORS(State.ON), + UPDATE(State.ON), + VALIDATION(State.OFF), + ENTITY_AI(State.OFF), + EVENTS(State.OFF); + + private final String displayName; + private final String description; + private final State defaultValue; + + SideEffect(State defaultValue) { + this.displayName = "worldedit.sideeffect." + this.name().toLowerCase(Locale.US); + this.description = "worldedit.sideeffect." + this.name().toLowerCase(Locale.US) + ".description"; + this.defaultValue = defaultValue; + } + + public String getDisplayName() { + return this.displayName; + } + + public String getDescription() { + return this.description; + } + + public State getDefaultValue() { + return this.defaultValue; + } + + public enum State { + OFF, + ON, + DELAYED; + + private final String displayName; + + State() { + this.displayName = "worldedit.sideeffect.state." + this.name().toLowerCase(Locale.US); + } + + public String getDisplayName() { + return this.displayName; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/SideEffectSet.java b/src/main/java/com/sk89q/worldedit/util/SideEffectSet.java new file mode 100644 index 0000000..ebf5f73 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/SideEffectSet.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +import java.util.Arrays; +import java.util.EnumMap; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class SideEffectSet { + private static final SideEffectSet DEFAULT = new SideEffectSet(ImmutableMap.of()); + private static final SideEffectSet NONE = new SideEffectSet( + Arrays.stream(SideEffect.values()).collect(Collectors.toMap(Function.identity(), state -> SideEffect.State.OFF)) + ); + + private final Map sideEffects; + private final Set appliedSideEffects; + private final boolean appliesAny; + + public SideEffectSet(Map sideEffects) { + this.sideEffects = Maps.immutableEnumMap(sideEffects); + + appliedSideEffects = sideEffects.entrySet() + .stream() + .filter(entry -> entry.getValue() != SideEffect.State.OFF) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + appliesAny = !appliedSideEffects.isEmpty(); + } + + public SideEffectSet with(SideEffect sideEffect, SideEffect.State state) { + Map entries = this.sideEffects.isEmpty() ? Maps.newEnumMap(SideEffect.class) : new EnumMap<>(this.sideEffects); + entries.put(sideEffect, state); + return new SideEffectSet(entries); + } + + public boolean doesApplyAny() { + return this.appliesAny; + } + + public SideEffect.State getState(SideEffect effect) { + return sideEffects.getOrDefault(effect, effect.getDefaultValue()); + } + + /** + * Gets whether this side effect is not off. + * + *

+ * This returns whether it is either delayed or on. + *

+ * + * @param effect The side effect + * @return Whether it should apply + */ + public boolean shouldApply(SideEffect effect) { + return getState(effect) != SideEffect.State.OFF; + } + + public Set getSideEffectsToApply() { + return this.appliedSideEffects; + } + + public static SideEffectSet defaults() { + return DEFAULT; + } + + public static SideEffectSet none() { + return NONE; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/TargetBlock.java b/src/main/java/com/sk89q/worldedit/util/TargetBlock.java new file mode 100644 index 0000000..f6e52e6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/TargetBlock.java @@ -0,0 +1,254 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.SolidBlockMask; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; + +/** + * This class uses an inefficient method to figure out what block a player + * is looking towards. + * + *

Originally written by toi. It was ported to WorldEdit and trimmed down by + * sk89q. Thanks to Raphfrk for optimization of toi's original class.

+ */ +public class TargetBlock { + + private final World world; + + private int maxDistance; + private double checkDistance; + private double curDistance; + private BlockVector3 targetPos = BlockVector3.ZERO; + private Vector3 targetPosDouble = Vector3.ZERO; + private BlockVector3 prevPos = BlockVector3.ZERO; + private Vector3 offset = Vector3.ZERO; + + // the mask which dictates when to stop a trace - defaults to stopping at non-air blocks + private Mask stopMask; + // the mask which dictates when to stop a solid block trace - default to BlockMaterial#isMovementBlocker + private Mask solidMask; + + /** + * Constructor requiring a player, uses default values. + * + * @param player player to work with + */ + public TargetBlock(Player player) { + this.world = player.getWorld(); + this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(), + 300, 1.65, 0.2); + this.stopMask = new ExistingBlockMask(world); + this.solidMask = new SolidBlockMask(world); + } + + /** + * Constructor requiring a player, max distance and a checking distance. + * + * @param player Player to work with + * @param maxDistance how far it checks for blocks + * @param checkDistance how often to check for blocks, the smaller the more precise + */ + public TargetBlock(Player player, int maxDistance, double checkDistance) { + this.world = player.getWorld(); + this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(), maxDistance, 1.65, checkDistance); + this.stopMask = new ExistingBlockMask(world); + this.solidMask = new SolidBlockMask(world); + } + + /** + * Set the mask used for determine where to stop traces. + * Setting to null will restore the default. + * + * @param stopMask the mask used to stop traces + */ + public void setStopMask(@Nullable Mask stopMask) { + if (stopMask == null) { + this.stopMask = new ExistingBlockMask(world); + } else { + this.stopMask = stopMask; + } + } + + /** + * Set the mask used for determine where to stop solid block traces. + * Setting to null will restore the default. + * + * @param solidMask the mask used to stop solid block traces + */ + public void setSolidMask(@Nullable Mask solidMask) { + if (solidMask == null) { + this.solidMask = new SolidBlockMask(world); + } else { + this.solidMask = solidMask; + } + } + + /** + * Set the values, all constructors uses this function. + * + * @param loc location of the view + * @param rotationX the X rotation + * @param rotationY the Y rotation + * @param maxDistance how far it checks for blocks + * @param viewHeight where the view is positioned in y-axis + * @param checkDistance how often to check for blocks, the smaller the more precise + */ + private void setValues(Vector3 loc, double rotationX, double rotationY, int maxDistance, double viewHeight, double checkDistance) { + this.maxDistance = maxDistance; + this.checkDistance = checkDistance; + this.curDistance = 0; + rotationX = (rotationX + 90) % 360; + rotationY *= -1; + + double h = (checkDistance * Math.cos(Math.toRadians(rotationY))); + + offset = Vector3.at((h * Math.cos(Math.toRadians(rotationX))), + (checkDistance * Math.sin(Math.toRadians(rotationY))), + (h * Math.sin(Math.toRadians(rotationX)))); + + targetPosDouble = loc.add(0, viewHeight, 0); + targetPos = targetPosDouble.toBlockPoint(); + prevPos = targetPos; + } + + /** + * Returns any block at the sight. Returns null if out of range or if no + * viable target was found. Will try to return the last valid air block it finds. + * + * @return Block + */ + public Location getAnyTargetBlock() { + Location lastBlock = null; + while (getNextBlock() != null) { + if (stopMask.test(targetPos)) { + break; + } else { + lastBlock = getCurrentBlock(); + if (lastBlock.getBlockY() < world.getMinY() + || lastBlock.getBlockY() > world.getMaxY()) { + return null; + } + } + } + Location currentBlock = getCurrentBlock(); + return (currentBlock != null ? currentBlock : lastBlock); + } + + /** + * Returns the block at the sight. Returns null if out of range or if no + * viable target was found + * + * @return Block + */ + public Location getTargetBlock() { + //noinspection StatementWithEmptyBody + while (getNextBlock() != null && !stopMask.test(targetPos)) { + } + return getCurrentBlock(); + } + + /** + * Returns the block at the sight. Returns null if out of range or if no + * viable target was found + * + * @return Block + */ + public Location getSolidTargetBlock() { + //noinspection StatementWithEmptyBody + while (getNextBlock() != null && !solidMask.test(targetPos)) { + } + return getCurrentBlock(); + } + + /** + * Get next block. + * + * @return next block position + */ + public Location getNextBlock() { + prevPos = targetPos; + do { + curDistance += checkDistance; + + targetPosDouble = offset.add(targetPosDouble.getX(), + targetPosDouble.getY(), + targetPosDouble.getZ()); + targetPos = targetPosDouble.toBlockPoint(); + } while (curDistance <= maxDistance + && targetPos.getBlockX() == prevPos.getBlockX() + && targetPos.getBlockY() == prevPos.getBlockY() + && targetPos.getBlockZ() == prevPos.getBlockZ()); + + if (curDistance > maxDistance) { + return null; + } + + return new Location(world, targetPos.toVector3()); + } + + /** + * Returns the current block along the line of vision. + * + * @return block position + */ + public Location getCurrentBlock() { + if (curDistance > maxDistance) { + return null; + } else { + return new Location(world, targetPos.toVector3()); + } + } + + /** + * Returns the previous block in the aimed path. + * + * @return block position + */ + public Location getPreviousBlock() { + return new Location(world, prevPos.toVector3()); + } + + public Location getAnyTargetBlockFace() { + getAnyTargetBlock(); + Location current = getCurrentBlock(); + if (current != null) { + return current.setDirection(current.toVector().subtract(getPreviousBlock().toVector())); + } else { + return new Location(world, targetPos.toVector3(), Float.NaN, Float.NaN); + } + } + + public Location getTargetBlockFace() { + getTargetBlock(); + if (getCurrentBlock() == null) { + return null; + } + return getCurrentBlock().setDirection(getCurrentBlock().toVector().subtract(getPreviousBlock().toVector())); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java b/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java new file mode 100644 index 0000000..0998a80 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java @@ -0,0 +1,276 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; +import java.util.*; + +/** + * Tree generator. + */ +public final class TreeGenerator { + + public enum TreeType { + TREE("Oak tree", "oak", "tree", "regular"), + BIG_TREE("Large oak tree", "largeoak", "bigoak", "big", "bigtree"), + REDWOOD("Spruce tree", "spruce", "redwood", "sequoia", "sequoioideae"), + TALL_REDWOOD("Tall spruce tree", "tallspruce", "bigspruce", "tallredwood", "tallsequoia", "tallsequoioideae"), + MEGA_REDWOOD("Large spruce tree", "largespruce", "megaredwood"), + RANDOM_REDWOOD("Random spruce tree", "randspruce", "randredwood", "randomredwood", "anyredwood") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + TreeType[] choices = { REDWOOD, TALL_REDWOOD, MEGA_REDWOOD }; + return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); + } + }, + BIRCH("Birch tree", "birch", "white", "whitebark"), + TALL_BIRCH("Tall birch tree", "tallbirch"), + RANDOM_BIRCH("Random birch tree", "randbirch", "randombirch") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + TreeType[] choices = { BIRCH, TALL_BIRCH }; + return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); + } + }, + JUNGLE("Jungle tree", "jungle"), + SMALL_JUNGLE("Small jungle tree", "smalljungle"), + SHORT_JUNGLE("Short jungle tree", "shortjungle") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + return SMALL_JUNGLE.generate(editSession, pos); + } + }, + RANDOM_JUNGLE("Random jungle tree", "randjungle", "randomjungle") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + TreeType[] choices = { JUNGLE, SMALL_JUNGLE }; + return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); + } + }, + JUNGLE_BUSH("Jungle bush", "junglebush", "jungleshrub"), + RED_MUSHROOM("Red mushroom", "redmushroom", "redgiantmushroom"), + BROWN_MUSHROOM("Brown mushroom", "brownmushroom", "browngiantmushroom"), + CRIMSON_FUNGUS("Crimson fungus", "crimsonfungus", "rednethermushroom"), + WARPED_FUNGUS("Warped fungus", "warpedfungus", "greennethermushroom"), + RANDOM_MUSHROOM("Random mushroom", "randmushroom", "randommushroom") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + TreeType[] choices = { RED_MUSHROOM, BROWN_MUSHROOM, CRIMSON_FUNGUS, WARPED_FUNGUS }; + return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); + } + }, + SWAMP("Swamp tree", "swamp", "swamptree"), + ACACIA("Acacia tree", "acacia"), + DARK_OAK("Dark oak tree", "darkoak"), + PINE("Pine tree", "pine") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + makePineTree(editSession, pos); + return true; + } + }, + CHORUS_PLANT("Chorus plant", "chorusplant") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + // chorus plants have to generate starting in the end stone itself, not the air above the ground + return editSession.getWorld().generateTree(this, editSession, pos.subtract(0, 1, 0)); + } + }, + MANGROVE("Mangrove tree", "mangrove"), + TALL_MANGROVE("Tall mangrove tree", "tall_mangrove"), + CHERRY("Cherry blossom", "cherry"), + RANDOM("Random tree", "rand", "random") { + @Override + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + TreeType[] choices = TreeType.values(); + return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos); + } + }; + + /** + * Stores a map of the names for fast access. + */ + private static final Map lookup = new HashMap<>(); + private static final Set primaryAliases = Sets.newHashSet(); + + private final String name; + public final ImmutableList lookupKeys; + + static { + for (TreeType type : EnumSet.allOf(TreeType.class)) { + for (String key : type.lookupKeys) { + lookup.put(key, type); + } + if (type.lookupKeys.size() > 0) { + primaryAliases.add(type.lookupKeys.get(0)); + } + } + } + + TreeType(String name, String... lookupKeys) { + this.name = name; + this.lookupKeys = ImmutableList.copyOf(lookupKeys); + } + + public static Set getAliases() { + return Collections.unmodifiableSet(lookup.keySet()); + } + + public static Set getPrimaryAliases() { + return Collections.unmodifiableSet(primaryAliases); + } + + public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { + return editSession.getWorld().generateTree(this, editSession, pos); + } + + /** + * Get user-friendly tree type name. + * + * @return a name + */ + public String getName() { + return name; + } + + /** + * Return type from name. May return null. + * + * @param name name to search + * @return a tree type or null + */ + @Nullable + public static TreeType lookup(String name) { + return lookup.get(name.toLowerCase(Locale.ROOT)); + } + } + + private TreeGenerator() { + } + + private static final Random RANDOM = new Random(); + + /** + * Makes a terrible looking pine tree. + * + * @param basePosition the base position + */ + private static void makePineTree(EditSession editSession, BlockVector3 basePosition) + throws MaxChangedBlocksException { + int trunkHeight = (int) Math.floor(Math.random() * 2) + 3; + int height = (int) Math.floor(Math.random() * 5) + 8; + + BlockState logBlock = BlockTypes.OAK_LOG.getDefaultState(); + BlockState leavesBlock = BlockTypes.OAK_LEAVES.getDefaultState(); + + // Create trunk + for (int i = 0; i < trunkHeight; ++i) { + if (!setBlockIfAir(editSession, basePosition.add(0, i, 0), logBlock)) { + return; + } + } + + // Move up + basePosition = basePosition.add(0, trunkHeight, 0); + + // Create tree + leaves + for (int i = 0; i < height; ++i) { + setBlockIfAir(editSession, basePosition.add(0, i, 0), logBlock); + + // Less leaves at these levels + double chance = ((i == 0 || i == height - 1) ? 0.6 : 1); + + // Inner leaves + setChanceBlockIfAir(editSession, basePosition.add(-1, i, 0), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(1, i, 0), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(0, i, -1), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(0, i, 1), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(1, i, 1), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(-1, i, 1), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(1, i, -1), leavesBlock, chance); + setChanceBlockIfAir(editSession, basePosition.add(-1, i, -1), leavesBlock, chance); + + if (!(i == 0 || i == height - 1)) { + for (int j = -2; j <= 2; ++j) { + setChanceBlockIfAir(editSession, basePosition.add(-2, i, j), leavesBlock, 0.6); + } + for (int j = -2; j <= 2; ++j) { + setChanceBlockIfAir(editSession, basePosition.add(2, i, j), leavesBlock, 0.6); + } + for (int j = -2; j <= 2; ++j) { + setChanceBlockIfAir(editSession, basePosition.add(j, i, -2), leavesBlock, 0.6); + } + for (int j = -2; j <= 2; ++j) { + setChanceBlockIfAir(editSession, basePosition.add(j, i, 2), leavesBlock, 0.6); + } + } + } + + setBlockIfAir(editSession, basePosition.add(0, height, 0), leavesBlock); + } + + /** + * Looks up a tree type. May return null if a tree type by that + * name is not found. + * + * @param type the tree type + * @return a tree type or null + */ + @Nullable + public static TreeType lookup(String type) { + return TreeType.lookup(type); + } + + /** + * Set a block (only if a previous block was not there) if {@link Math#random()} + * returns a number less than the given probability. + * + * @param position the position + * @param block the block + * @param probability a probability between 0 and 1, inclusive + * @return whether a block was changed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + private static > boolean setChanceBlockIfAir(EditSession session, BlockVector3 position, B block, double probability) + throws MaxChangedBlocksException { + return Math.random() <= probability && setBlockIfAir(session, position, block); + } + + /** + * Set a block only if there's no block already there. + * + * @param position the position + * @param block the block to set + * @return if block was changed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + private static > boolean setBlockIfAir(EditSession session, BlockVector3 position, B block) throws MaxChangedBlocksException { + return session.getBlock(position).getBlockType().getMaterial().isAir() && session.setBlock(position, block); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/WeightedChoice.java b/src/main/java/com/sk89q/worldedit/util/WeightedChoice.java new file mode 100644 index 0000000..49329e5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/WeightedChoice.java @@ -0,0 +1,116 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import java.util.Optional; +import java.util.function.Function; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Returns the best choice given a weighting function and a target weight. + * + *

A function must be supplied that returns a numeric score for each + * choice. The function can return null to mean that the choice should + * not be considered.

+ * + * @param the type of choice + */ +public class WeightedChoice { + + private final Function function; + private final double target; + private double best; + private T current; + + /** + * Create a new instance. + * + * @param function a function that assigns a score for each choice + * @param target the target score that the best choice should be closest to + */ + public WeightedChoice(Function function, double target) { + checkNotNull(function); + this.function = function; + this.target = target; + } + + /** + * Consider the given object. + * + * @param object the choice + */ + public void consider(T object) { + checkNotNull(object); + Number value = checkNotNull(function.apply(object)); + double distance = Math.abs(target - value.doubleValue()); + if (current == null || distance <= best) { + best = distance; + current = object; + } + } + + /** + * Get the best choice. + * + * @return the best choice + */ + public Optional> getChoice() { + if (current != null) { + return Optional.of(new Choice<>(current, best)); + } else { + return Optional.empty(); + } + } + + /** + * A tuple of choice and score. + * + * @param the choice type + */ + public static class Choice { + private final T object; + private final double value; + + private Choice(T object, double value) { + this.object = object; + this.value = value; + } + + /** + * Get the chosen value. + * + * @return the value + */ + public T getValue() { + return object; + } + + /** + * Get the score. + * + * @return the score + */ + public double getScore() { + return value; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java b/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java new file mode 100644 index 0000000..9c11922 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java @@ -0,0 +1,139 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util; + +import com.google.common.collect.Lists; +import com.sk89q.util.yaml.YAMLProcessor; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.session.SessionManager; +import com.sk89q.worldedit.util.report.Unreported; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Locale; + +/** + * A less simple implementation of {@link LocalConfiguration} + * using YAML configuration files. + */ +public class YAMLConfiguration extends LocalConfiguration { + + @Unreported protected final YAMLProcessor config; + @Unreported protected final Logger logger; + + public YAMLConfiguration(YAMLProcessor config, Logger logger) { + this.config = config; + this.logger = logger; + } + + @Override + public void load() { + try { + config.load(); + } catch (IOException e) { + logger.warn("Error loading WorldEdit configuration", e); + } + + profile = config.getBoolean("debug", profile); + traceUnflushedSessions = config.getBoolean("debugging.trace-unflushed-sessions", traceUnflushedSessions); + wandItem = convertLegacyItem(config.getString("wand-item", wandItem)).toLowerCase(Locale.ROOT); + + defaultChangeLimit = Math.max(-1, config.getInt( + "limits.max-blocks-changed.default", defaultChangeLimit)); + maxChangeLimit = Math.max(-1, + config.getInt("limits.max-blocks-changed.maximum", maxChangeLimit)); + + defaultVerticalHeight = Math.max(1, + config.getInt("limits.vertical-height.default", defaultVerticalHeight)); + + defaultMaxPolygonalPoints = Math.max(-1, + config.getInt("limits.max-polygonal-points.default", defaultMaxPolygonalPoints)); + maxPolygonalPoints = Math.max(-1, + config.getInt("limits.max-polygonal-points.maximum", maxPolygonalPoints)); + + defaultMaxPolyhedronPoints = Math.max(-1, config.getInt("limits.max-polyhedron-points.default", defaultMaxPolyhedronPoints)); + maxPolyhedronPoints = Math.max(-1, config.getInt("limits.max-polyhedron-points.maximum", maxPolyhedronPoints)); + + maxRadius = Math.max(-1, config.getInt("limits.max-radius", maxRadius)); + maxBrushRadius = config.getInt("limits.max-brush-radius", maxBrushRadius); + maxSuperPickaxeSize = Math.max(1, config.getInt( + "limits.max-super-pickaxe-size", maxSuperPickaxeSize)); + + butcherDefaultRadius = Math.max(-1, config.getInt("limits.butcher-radius.default", butcherDefaultRadius)); + butcherMaxRadius = Math.max(-1, config.getInt("limits.butcher-radius.maximum", butcherMaxRadius)); + + disallowedBlocks = new HashSet<>(config.getStringList("limits.disallowed-blocks", Lists.newArrayList(getDefaultDisallowedBlocks()))); + allowedDataCycleBlocks = new HashSet<>(config.getStringList("limits.allowed-data-cycle-blocks", null)); + + registerHelp = config.getBoolean("register-help", true); + logCommands = config.getBoolean("logging.log-commands", logCommands); + logFile = config.getString("logging.file", logFile); + logFormat = config.getString("logging.format", logFormat); + + superPickaxeDrop = config.getBoolean("super-pickaxe.drop-items", + superPickaxeDrop); + superPickaxeManyDrop = config.getBoolean( + "super-pickaxe.many-drop-items", superPickaxeManyDrop); + + useInventory = config.getBoolean("use-inventory.enable", useInventory); + useInventoryOverride = config.getBoolean("use-inventory.allow-override", + useInventoryOverride); + useInventoryCreativeOverride = config.getBoolean("use-inventory.creative-mode-overrides", + useInventoryCreativeOverride); + + navigationWand = convertLegacyItem(config.getString("navigation-wand.item", navigationWand)).toLowerCase(Locale.ROOT); + navigationWandMaxDistance = config.getInt("navigation-wand.max-distance", navigationWandMaxDistance); + navigationUseGlass = config.getBoolean("navigation.use-glass", navigationUseGlass); + + scriptTimeout = config.getInt("scripting.timeout", scriptTimeout); + scriptsDir = config.getString("scripting.dir", scriptsDir); + + calculationTimeout = config.getInt("calculation.timeout", calculationTimeout); + maxCalculationTimeout = config.getInt("calculation.max-timeout", maxCalculationTimeout); + + saveDir = config.getString("saving.dir", saveDir); + + allowSymlinks = config.getBoolean("files.allow-symbolic-links", false); + LocalSession.MAX_HISTORY_SIZE = Math.max(0, config.getInt("history.size", 15)); + SessionManager.EXPIRATION_GRACE = config.getInt("history.expiration", 10) * 60 * 1000; + + showHelpInfo = config.getBoolean("show-help-on-first-use", true); + serverSideCUI = config.getBoolean("server-side-cui", true); + + String snapshotsDir = config.getString("snapshots.directory", ""); + boolean experimentalSnapshots = config.getBoolean("snapshots.experimental", false); + initializeSnapshotConfiguration(snapshotsDir, experimentalSnapshots); + + String type = config.getString("shell-save-type", "").trim(); + shellSaveType = type.isEmpty() ? null : type; + + extendedYLimit = config.getBoolean("compat.extended-y-limit", false); + + setDefaultLocaleName(config.getString("default-locale", defaultLocaleName)); + + commandBlockSupport = config.getBoolean("command-block-support", false); + } + + public void unload() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/asset/AssetLoadTask.java b/src/main/java/com/sk89q/worldedit/util/asset/AssetLoadTask.java new file mode 100644 index 0000000..ce8e77c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/asset/AssetLoadTask.java @@ -0,0 +1,55 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.asset; + +import com.sk89q.worldedit.command.util.AsyncCommandBuilder; + +import java.util.concurrent.Callable; + +/** + * A Callable to load an asset by name. + * + *

+ * This is intended to be used with {@link AsyncCommandBuilder} for loading assets in commands. + *

+ * + * @param The asset type + */ +public class AssetLoadTask implements Callable { + + private final String assetName; + private final AssetLoader loader; + + /** + * Creates an asset load task with the given loader and asset name. + * + * @param loader The asset loader + * @param assetName The asset name + */ + public AssetLoadTask(AssetLoader loader, String assetName) { + this.loader = loader; + this.assetName = assetName; + } + + @Override + public T call() { + return this.loader.getAsset(this.assetName); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/asset/AssetLoader.java b/src/main/java/com/sk89q/worldedit/util/asset/AssetLoader.java new file mode 100644 index 0000000..e1621bd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/asset/AssetLoader.java @@ -0,0 +1,111 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.asset; + +import com.google.common.annotations.Beta; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.util.io.file.FilenameException; + +import javax.annotation.Nullable; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +@Beta +public abstract class AssetLoader { + + private final Cache assets = CacheBuilder.newBuilder() + .expireAfterAccess(5, TimeUnit.MINUTES) + .build(); + + private final WorldEdit worldEdit; + private final Path assetDir; + + public AssetLoader(WorldEdit worldEdit, Path assetDir) { + this.worldEdit = worldEdit; + this.assetDir = assetDir; + } + + /** + * Loads an asset. + * + * @param path path in assets directory, can be with and without its file extension + * @return asset if successfully loaded, null otherwise + */ + @Nullable + public T getAsset(String path) { + T cached = assets.getIfPresent(path); + if (cached != null) { + return cached; + } + + if (!Files.isDirectory(this.assetDir)) { + return null; + } + + String[] extensions = this.getAllowedExtensions().toArray(new String[0]); + + Path file; + try { + file = worldEdit.getSafeOpenFile( + null, + this.assetDir.toFile(), + path, + extensions[0], + extensions + ).toPath(); + } catch (FilenameException e) { + return null; + } + + T asset; + try { + asset = loadAssetFromPath(file); + if (asset == null) { + return null; + } + } catch (Exception e) { + WorldEdit.logger.error("Error reading asset file directory", e); + return null; + } + + assets.put(path, asset); + return asset; + } + + /** + * Loads an asset from the given file if possible. + * + * @param path The file to load + * @return loaded asset, or null otherwise + */ + @Nullable + protected abstract T loadAssetFromPath(Path path) throws Exception; + + /** + * The extensions that this asset loader supports. + * + * @return The supported extensions + */ + public abstract Set getAllowedExtensions(); +} diff --git a/src/main/java/com/sk89q/worldedit/util/asset/AssetLoaders.java b/src/main/java/com/sk89q/worldedit/util/asset/AssetLoaders.java new file mode 100644 index 0000000..249a443 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/asset/AssetLoaders.java @@ -0,0 +1,172 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.asset; + +import com.google.common.annotations.Beta; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Table; +import com.google.common.io.MoreFiles; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.util.asset.holder.ImageHeightmap; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * Class to store the various asset loaders. + */ +@Beta +public class AssetLoaders { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final List> assetLoaders = Lists.newArrayList(); + private final Table, String, AssetLoader> assetLoaderRegistration = HashBasedTable.create(); + private final WorldEdit worldEdit; + + private Path assetsDir; + + /** + * Creates a new AssetManager to load and cache custom assets. + * + * @param worldEdit WorldEdit instance + */ + public AssetLoaders(WorldEdit worldEdit) { + this.worldEdit = worldEdit; + } + + public void init() { + this.assetsDir = worldEdit.getWorkingDirectoryPath("assets"); + + try { + Files.createDirectories(this.assetsDir); + } catch (IOException e) { + LOGGER.warn("Failed to create asset directory", e); + } + + registerAssetLoader(new ImageHeightmapLoader(worldEdit, this.assetsDir), ImageHeightmap.class); + } + + public void uninit() { + this.assetsDir = null; + assetLoaderRegistration.clear(); + } + + public void registerAssetLoader(AssetLoader loader, Class assetClass) { + assetLoaders.add(loader); + for (String extension : loader.getAllowedExtensions()) { + if (assetLoaderRegistration.contains(assetClass, extension)) { + LOGGER.warn(String.format( + "Tried to register asset loader '%s' with extension '%s' and asset class '%s', but it is already registered to '%s'", + loader.getClass().getName(), + extension, + assetClass.getName(), + assetLoaderRegistration.get(assetClass, extension).getClass().getName() + )); + continue; + } + + assetLoaderRegistration.put(assetClass, extension, loader); + } + } + + /** + * Gets the Asset Loader for the given file of the given type. + * + * @param assetClass The class to get a loader for + * @param filename The filename to attempt to load + * @param The returned asset type + */ + @SuppressWarnings("unchecked") + public Optional> getAssetLoader(Class assetClass, String filename) { + if (!assetLoaderRegistration.containsRow(assetClass)) { + return Optional.empty(); + } + + Path directPath = this.assetsDir.resolve(filename); + + String ext = MoreFiles.getFileExtension(directPath); + if (Files.exists(directPath) && assetLoaderRegistration.contains(assetClass, ext)) { + return Optional.ofNullable((AssetLoader) assetLoaderRegistration.get(assetClass, ext)); + } + + for (Map.Entry> entry : assetLoaderRegistration.row(assetClass).entrySet()) { + Path extensionPath = this.assetsDir.resolve(filename + "." + entry.getKey()); + if (Files.exists(extensionPath)) { + return Optional.ofNullable((AssetLoader) entry.getValue()); + } + } + + return Optional.empty(); + } + + /** + * Get the Asset Loaders for the given type. + * + * @param assetClass The class to get the loaders of + * @param The asset type + * @return The list of asset loaders + */ + @SuppressWarnings("unchecked") + public List> getAssetLoaders(Class assetClass) { + if (!assetLoaderRegistration.containsRow(assetClass)) { + return ImmutableList.of(); + } + + return ImmutableList.copyOf((Collection>) (Collection) assetLoaderRegistration.row(assetClass).values()); + } + + /** + * Gets an immutable list of all files that match a certain asset type. + * + * @param assetClass The asset class + * @return The list of files + */ + public List getFilesForAsset(Class assetClass) { + Set extensions = this.assetLoaderRegistration.row(assetClass).keySet(); + + try (DirectoryStream stream = Files.newDirectoryStream(this.assetsDir, entry -> extensions.contains(MoreFiles.getFileExtension(entry)))) { + return ImmutableList.copyOf(stream); + } catch (IOException e) { + LOGGER.warn("Failed to get files for asset type " + assetClass.getName(), e); + return ImmutableList.of(); + } + } + + /** + * Gets an immutable copy of all registered asset loaders. + * + * @return The asset loaders + */ + public List> getAssetLoaders() { + return ImmutableList.copyOf(assetLoaders); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/asset/ImageHeightmapLoader.java b/src/main/java/com/sk89q/worldedit/util/asset/ImageHeightmapLoader.java new file mode 100644 index 0000000..03f816c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/asset/ImageHeightmapLoader.java @@ -0,0 +1,55 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.asset; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.util.asset.holder.ImageHeightmap; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import javax.annotation.Nullable; +import javax.imageio.ImageIO; + +/** + * Loads and caches image files from WorldEdit's assets directory. + */ +@Beta +public class ImageHeightmapLoader extends AssetLoader { + + public ImageHeightmapLoader(WorldEdit worldEdit, Path assetDir) { + super(worldEdit, assetDir); + } + + @Nullable + public ImageHeightmap loadAssetFromPath(Path path) throws Exception { + if (!Files.exists(path)) { + return null; + } + return new ImageHeightmap(ImageIO.read(path.toFile())); + } + + @Override + public Set getAllowedExtensions() { + return ImmutableSet.copyOf(ImageIO.getReaderFileSuffixes()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/asset/holder/ImageHeightmap.java b/src/main/java/com/sk89q/worldedit/util/asset/holder/ImageHeightmap.java new file mode 100644 index 0000000..426fb3b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/asset/holder/ImageHeightmap.java @@ -0,0 +1,90 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.asset.holder; + +import com.google.common.annotations.Beta; + +import java.awt.*; +import java.awt.image.BufferedImage; + +/** + * Represents an image that acts as a heightmap. + * + *

+ * Height is determined by how light each pixel of the image is, + * from black (0) to white (1). Lightness is determined by an + * average of the 3 color channels. + *

+ */ +@Beta +public class ImageHeightmap { + + private final BufferedImage image; + + private BufferedImage resizedImage; + private int lastSize = -1; + + /** + * Create a new image heightmap from an image. + * + * @param image The image + */ + public ImageHeightmap(BufferedImage image) { + this.image = image; + } + + /** + * Gets the height at the given position with scaling applied. + * + * @param x The x position + * @param y The y position + * @param size The size to sample the image as + * @return The height at the location + */ + public double getHeightAt(int x, int y, int size) { + if (size != lastSize || resizedImage == null) { + resizedImage = new BufferedImage(size, size, 1); + Graphics2D graphic = null; + try { + graphic = resizedImage.createGraphics(); + graphic.drawImage(this.image, 0, 0, size, size, null); + } finally { + if (graphic != null) { + graphic.dispose(); + } + } + lastSize = size; + } + + // Flip the Y axis + y = resizedImage.getHeight() - 1 - y; + + int rgb = resizedImage.getRGB(x, y); + if (rgb == 0) { + return 0; + } + + int red = rgb >>> 16 & 0xFF; + int green = rgb >>> 8 & 0xFF; + int blue = rgb & 0xFF; + + return (red + blue + green) / 3D / 255D; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/auth/AuthorizationException.java b/src/main/java/com/sk89q/worldedit/util/auth/AuthorizationException.java new file mode 100644 index 0000000..9f07197 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/auth/AuthorizationException.java @@ -0,0 +1,54 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.auth; + +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.Component; + +/** + * Raised when authorization is not granted. + */ +public class AuthorizationException extends WorldEditException { + + public AuthorizationException() { + } + + public AuthorizationException(Component message) { + super(message); + } + + @Deprecated + public AuthorizationException(String message) { + super(message); + } + + public AuthorizationException(Component message, Throwable cause) { + super(message, cause); + } + + @Deprecated + public AuthorizationException(String message, Throwable cause) { + super(message, cause); + } + + public AuthorizationException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/auth/Authorizer.java b/src/main/java/com/sk89q/worldedit/util/auth/Authorizer.java new file mode 100644 index 0000000..72a4946 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/auth/Authorizer.java @@ -0,0 +1,38 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.auth; + +import com.sk89q.minecraft.util.commands.CommandLocals; + +/** + * Tests whether permission is granted. + */ +public interface Authorizer { + + /** + * Tests whether permission is granted for the given context. + * + * @param locals locals + * @param permission the permission string + * @return true if permitted + */ + boolean testPermission(CommandLocals locals, String permission); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/auth/NullAuthorizer.java b/src/main/java/com/sk89q/worldedit/util/auth/NullAuthorizer.java new file mode 100644 index 0000000..2f3b47c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/auth/NullAuthorizer.java @@ -0,0 +1,35 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.auth; + +import com.sk89q.minecraft.util.commands.CommandLocals; + +/** + * An implementation of {@link Authorizer} that always returns false for + * tests of permissions. + */ +public class NullAuthorizer implements Authorizer { + + @Override + public boolean testPermission(CommandLocals locals, String permission) { + return false; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/auth/Subject.java b/src/main/java/com/sk89q/worldedit/util/auth/Subject.java new file mode 100644 index 0000000..e1e837b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/auth/Subject.java @@ -0,0 +1,51 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.auth; + +/** + * A subject has authorization attached to it. + */ +public interface Subject { + + /** + * Get a list of groups that this subject is a part of. + * + * @return an array containing a group name per entry + */ + String[] getGroups(); + + /** + * Check whether this subject has been granted the given permission + * and throw an exception on error. + * + * @param permission the permission + * @throws AuthorizationException thrown if not permitted + */ + void checkPermission(String permission) throws AuthorizationException; + + /** + * Return whether this subject has the given permission. + * + * @param permission the permission + * @return true if permission is granted + */ + boolean hasPermission(String permission); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java b/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java new file mode 100644 index 0000000..872dd98 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java @@ -0,0 +1,472 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.collection; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectIterator; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; + +import static com.google.common.base.Preconditions.checkState; +import static com.sk89q.worldedit.math.BitMath.fixSign; +import static com.sk89q.worldedit.math.BitMath.mask; + +/** + * A space-efficient map implementation for block locations. + */ +public class BlockMap extends AbstractMap { + + public static BlockMap create() { + return create(() -> new Int2ObjectOpenHashMap<>(64, 0.9f)); + } + + public static BlockMap createForBaseBlock() { + return create(Int2BaseBlockMap::new); + } + + private static BlockMap create(Supplier> subMapSupplier) { + return new BlockMap<>(subMapSupplier); + } + + public static BlockMap copyOf(Map source) { + return new BlockMap<>(Int2ObjectOpenHashMap::new, source); + } + + /* + * Stores blocks by sub-dividing them into smaller groups. + * A block location is 26 bits long for x + z, and usually + * 8 bits for y, although mods such as cubic chunks may + * expand this to infinite. We support up to 32 bits of y. + * + * Grouping key stores 20 bits x + z, 24 bits y. + * Inner key stores 6 bits x + z, 8 bits y. + * Order (lowest to highest) is x-z-y. + */ + + private static final long BITS_24 = mask(24); + private static final long BITS_20 = mask(20); + private static final int BITS_8 = mask(8); + private static final int BITS_6 = mask(6); + + private static long toGroupKey(BlockVector3 location) { + return ((location.getX() >>> 6) & BITS_20) + | (((location.getZ() >>> 6) & BITS_20) << 20) + | (((location.getY() >>> 8) & BITS_24) << (20 + 20)); + } + + private static int toInnerKey(BlockVector3 location) { + return (location.getX() & BITS_6) + | ((location.getZ() & BITS_6) << 6) + | ((location.getY() & BITS_8) << (6 + 6)); + } + + private static final long GROUP_X = BITS_20; + private static final long GROUP_Z = BITS_20 << 20; + private static final long GROUP_Y = BITS_24 << (20 + 20); + private static final int INNER_X = BITS_6; + private static final int INNER_Z = BITS_6 << 6; + private static final int INNER_Y = BITS_8 << (6 + 6); + + private static BlockVector3 reconstructLocation(long group, int inner) { + int groupX = (int) ((group & GROUP_X) << 6); + int x = fixSign(groupX | (inner & INNER_X), 26); + int groupZ = (int) ((group & GROUP_Z) >>> (20 - 6)); + int z = fixSign(groupZ | ((inner & INNER_Z) >>> 6), 26); + int groupY = (int) ((group & GROUP_Y) >>> (20 + 20 - 8)); + int y = groupY | ((inner & INNER_Y) >>> (6 + 6)); + return BlockVector3.at(x, y, z); + } + + private final Long2ObjectMap> maps = new Long2ObjectOpenHashMap<>(4, 0.75f); + private final Supplier> subMapSupplier; + private Set> entrySet; + private Collection values; + + private BlockMap(Supplier> subMapSupplier) { + this.subMapSupplier = subMapSupplier; + } + + private BlockMap(Supplier> subMapSupplier, Map source) { + this.subMapSupplier = subMapSupplier; + putAll(source); + } + + private Int2ObjectMap getOrCreateMap(long groupKey) { + return maps.computeIfAbsent(groupKey, k -> subMapSupplier.get()); + } + + private Int2ObjectMap getOrEmptyMap(long groupKey) { + return maps.getOrDefault(groupKey, Int2ObjectMaps.emptyMap()); + } + + /** + * Apply the function the the map at {@code groupKey}, and if the function empties the map, + * delete it from {@code maps}. + */ + private R cleanlyModifyMap(long groupKey, Function, R> func) { + Int2ObjectMap map = maps.get(groupKey); + if (map != null) { + R result = func.apply(map); + if (map.isEmpty()) { + maps.remove(groupKey); + } + return result; + } + map = subMapSupplier.get(); + R result = func.apply(map); + if (!map.isEmpty()) { + maps.put(groupKey, map); + } + return result; + } + + @Override + public V put(BlockVector3 key, V value) { + return getOrCreateMap(toGroupKey(key)).put(toInnerKey(key), value); + } + + @Override + public V getOrDefault(Object key, V defaultValue) { + BlockVector3 vec = (BlockVector3) key; + return getOrEmptyMap(toGroupKey(vec)) + .getOrDefault(toInnerKey(vec), defaultValue); + } + + @Override + public void forEach(BiConsumer action) { + maps.forEach((groupKey, m) -> + m.forEach((innerKey, block) -> + action.accept(reconstructLocation(groupKey, innerKey), block) + ) + ); + } + + @Override + public void replaceAll(BiFunction function) { + maps.forEach((groupKey, m) -> + m.replaceAll((innerKey, block) -> + function.apply(reconstructLocation(groupKey, innerKey), block) + ) + ); + } + + @Override + public V putIfAbsent(BlockVector3 key, V value) { + return getOrCreateMap(toGroupKey(key)).putIfAbsent(toInnerKey(key), value); + } + + @Override + public boolean remove(Object key, Object value) { + BlockVector3 vec = (BlockVector3) key; + return cleanlyModifyMap(toGroupKey(vec), + map -> map.remove(toInnerKey(vec), value)); + } + + @Override + public boolean replace(BlockVector3 key, V oldValue, V newValue) { + return cleanlyModifyMap(toGroupKey(key), + map -> map.replace(toInnerKey(key), oldValue, newValue)); + } + + @Override + public V replace(BlockVector3 key, V value) { + return getOrCreateMap(toGroupKey(key)).replace(toInnerKey(key), value); + } + + @Override + public V computeIfAbsent(BlockVector3 key, Function mappingFunction) { + return cleanlyModifyMap(toGroupKey(key), + map -> map.computeIfAbsent(toInnerKey(key), ik -> mappingFunction.apply(key))); + } + + @Override + public V computeIfPresent(BlockVector3 key, BiFunction remappingFunction) { + return cleanlyModifyMap(toGroupKey(key), + map -> map.computeIfPresent(toInnerKey(key), (ik, block) -> remappingFunction.apply(key, block))); + } + + @Override + public V compute(BlockVector3 key, BiFunction remappingFunction) { + return cleanlyModifyMap(toGroupKey(key), + map -> map.compute(toInnerKey(key), (ik, block) -> remappingFunction.apply(key, block))); + } + + @Override + public V merge(BlockVector3 key, V value, BiFunction remappingFunction) { + return cleanlyModifyMap(toGroupKey(key), + map -> map.merge(toInnerKey(key), value, remappingFunction)); + } + + @Override + public Set> entrySet() { + Set> es = entrySet; + if (es == null) { + entrySet = es = new AbstractSet>() { + @Override + public Iterator> iterator() { + return new Iterator>() { + + private final ObjectIterator>> primaryIterator + = Long2ObjectMaps.fastIterator(maps); + private Long2ObjectMap.Entry> currentPrimaryEntry; + private ObjectIterator> secondaryIterator; + private boolean finished; + private LazyEntry next; + + @Override + public boolean hasNext() { + if (finished) { + return false; + } + if (next == null) { + LazyEntry proposedNext = computeNext(); + if (proposedNext == null) { + finished = true; + return false; + } + next = proposedNext; + } + return true; + } + + private LazyEntry computeNext() { + if (secondaryIterator == null || !secondaryIterator.hasNext()) { + if (!primaryIterator.hasNext()) { + return null; + } + + currentPrimaryEntry = primaryIterator.next(); + secondaryIterator = Int2ObjectMaps.fastIterator(currentPrimaryEntry.getValue()); + // be paranoid + checkState(secondaryIterator.hasNext(), + "Should not have an empty map entry, it should have been removed!"); + } + Int2ObjectMap.Entry next = secondaryIterator.next(); + return new LazyEntry(currentPrimaryEntry.getLongKey(), next.getIntKey(), next.getValue()); + } + + @Override + public Entry next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + LazyEntry tmp = next; + next = null; + return tmp; + } + + @Override + public void remove() { + secondaryIterator.remove(); + // ensure invariants hold + if (currentPrimaryEntry.getValue().isEmpty()) { + // the remove call cleared this map. call remove on the primary iter + primaryIterator.remove(); + } + } + }; + } + + @Override + public int size() { + return BlockMap.this.size(); + } + }; + } + return es; + } + + private final class LazyEntry implements Entry { + + private final long groupKey; + private final int innerKey; + private BlockVector3 lazyKey; + private V value; + + private LazyEntry(long groupKey, int innerKey, V value) { + this.groupKey = groupKey; + this.innerKey = innerKey; + this.value = value; + } + + @Override + public BlockVector3 getKey() { + BlockVector3 result = lazyKey; + if (result == null) { + lazyKey = result = reconstructLocation(groupKey, innerKey); + } + return result; + } + + @Override + public V getValue() { + return value; + } + + @Override + public V setValue(V value) { + this.value = value; + return getOrCreateMap(groupKey).put(innerKey, value); + } + + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) { + return false; + } + Entry e = (Entry) o; + if (o instanceof BlockMap.LazyEntry) { + @SuppressWarnings("unchecked") + LazyEntry otherE = (LazyEntry) o; + return otherE.groupKey == groupKey + && otherE.innerKey == innerKey + && Objects.equals(value, e.getValue()); + } + return Objects.equals(getKey(), e.getKey()) && Objects.equals(value, e.getValue()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getKey()) ^ Objects.hashCode(value); + } + + @Override + public String toString() { + return getKey() + "=" + getValue(); + } + } + + @Override + public boolean containsValue(Object value) { + return maps.values().stream().anyMatch(m -> m.containsValue(value)); + } + + @Override + public boolean containsKey(Object key) { + BlockVector3 vec = (BlockVector3) key; + Int2ObjectMap activeMap = maps.get(toGroupKey(vec)); + if (activeMap == null) { + return false; + } + return activeMap.containsKey(toInnerKey(vec)); + } + + @Override + public V get(Object key) { + BlockVector3 vec = (BlockVector3) key; + Int2ObjectMap activeMap = maps.get(toGroupKey(vec)); + if (activeMap == null) { + return null; + } + return activeMap.get(toInnerKey(vec)); + } + + @Override + public V remove(Object key) { + BlockVector3 vec = (BlockVector3) key; + long groupKey = toGroupKey(vec); + Int2ObjectMap activeMap = maps.get(groupKey); + if (activeMap == null) { + return null; + } + V removed = activeMap.remove(toInnerKey(vec)); + if (activeMap.isEmpty()) { + maps.remove(groupKey); + } + return removed; + } + + @SuppressWarnings("unchecked") + @Override + public void putAll(Map m) { + if (m instanceof BlockMap) { + // optimize insertions: + ((BlockMap) m).maps.forEach((groupKey, map) -> + getOrCreateMap(groupKey).putAll(map) + ); + } else { + super.putAll(m); + } + } + + @Override + public void clear() { + maps.clear(); + } + + @Override + public int size() { + return maps.values().stream().mapToInt(Map::size).sum(); + } + + // no keySet override, since we can't really optimize it. + // we can optimize values access though, by skipping BV construction. + + @Override + public Collection values() { + Collection vs = values; + if (vs == null) { + values = vs = new AbstractCollection() { + @Override + public Iterator iterator() { + return maps.values().stream() + .flatMap(m -> m.values().stream()) + .iterator(); + } + + @Override + public int size() { + return BlockMap.this.size(); + } + }; + } + return vs; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof BlockMap) { + // optimize by skipping entry translations: + @SuppressWarnings("unchecked") + BlockMap other = (BlockMap) o; + return maps.equals(other.maps); + } + return super.equals(o); + } + + // satisfy checkstyle + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/collection/DoubleArrayList.java b/src/main/java/com/sk89q/worldedit/util/collection/DoubleArrayList.java new file mode 100644 index 0000000..09e3926 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/collection/DoubleArrayList.java @@ -0,0 +1,182 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.collection; + +import java.util.*; + +/** + * Double array lists to work like a Map, but not really. + * + *

The usefulness of this class is highly questionable.

+ */ +public class DoubleArrayList implements Iterable> { + + private final List listA = new ArrayList<>(); + private final List listB = new ArrayList<>(); + private boolean isReversed = false; + + /** + * Construct the object. + * + * @param isReversed true if the list should be reversed + */ + public DoubleArrayList(boolean isReversed) { + this.isReversed = isReversed; + } + + /** + * Add an item. + * + * @param a the first item + * @param b the second item + */ + public void put(A a, B b) { + listA.add(a); + listB.add(b); + } + + /** + * Get size. + * + * @return count of objects + */ + public int size() { + return listA.size(); + } + + /** + * Clear the list. + */ + public void clear() { + listA.clear(); + listB.clear(); + } + + /** + * Get an entry set. + * + * @return entry set + */ + public Iterator> iterator(boolean reversed) { + if (reversed) { + return new ReverseEntryIterator<>( + listA.listIterator(listA.size()), + listB.listIterator(listB.size())); + } else { + return new ForwardEntryIterator<>( + listA.iterator(), + listB.iterator()); + } + } + + @Override + public Iterator> iterator() { + return iterator(isReversed); + } + + /** + * Entry iterator. + */ + public class ForwardEntryIterator> + implements Iterator> { + + private final Iterator keyIterator; + private final Iterator valueIterator; + + public ForwardEntryIterator(Iterator keyIterator, Iterator valueIterator) { + this.keyIterator = keyIterator; + this.valueIterator = valueIterator; + } + + @Override + public boolean hasNext() { + return keyIterator.hasNext(); + } + + @Override + public Map.Entry next() throws NoSuchElementException { + return new Entry(keyIterator.next(), valueIterator.next()); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Entry iterator. + */ + public class ReverseEntryIterator> + implements Iterator> { + + private final ListIterator keyIterator; + private final ListIterator valueIterator; + + public ReverseEntryIterator(ListIterator keyIterator, ListIterator valueIterator) { + this.keyIterator = keyIterator; + this.valueIterator = valueIterator; + } + + @Override + public boolean hasNext() { + return keyIterator.hasPrevious(); + } + + @Override + public Map.Entry next() throws NoSuchElementException { + return new Entry(keyIterator.previous(), valueIterator.previous()); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Class to masquerade as Map.Entry. + */ + public class Entry implements Map.Entry { + private final A key; + private final B value; + + private Entry(A key, B value) { + this.key = key; + this.value = value; + } + + @Override + public A getKey() { + return key; + } + + @Override + public B getValue() { + return value; + } + + @Override + public B setValue(B value) { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/collection/Int2BaseBlockMap.java b/src/main/java/com/sk89q/worldedit/util/collection/Int2BaseBlockMap.java new file mode 100644 index 0000000..556f277 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/collection/Int2BaseBlockMap.java @@ -0,0 +1,211 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.collection; + +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import it.unimi.dsi.fastutil.ints.AbstractInt2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntMaps; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.AbstractObjectSet; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectSet; + +import java.util.NoSuchElementException; +import java.util.function.BiFunction; +import javax.annotation.Nonnull; + +/** + * Int-to-BaseBlock map, but with optimizations for common cases. + */ +class Int2BaseBlockMap extends AbstractInt2ObjectMap { + + /** + * Given a {@link BaseBlock}, retrieve the internal ID if it's useful, + * i.e. the block has no NBT data. + * + * @param block the block to get the ID for + * @return the internal ID, or {@link BlockStateIdAccess#invalidId()} if not useful + */ + private static int optimizedInternalId(BaseBlock block) { + if (block.hasNbtData()) { + return BlockStateIdAccess.invalidId(); + } + return BlockStateIdAccess.getBlockStateId(block.toImmutableState()); + } + + private static BaseBlock assumeAsBlock(int id) { + if (!BlockStateIdAccess.isValidInternalId(id)) { + return null; + } + BlockState state = BlockStateIdAccess.getBlockStateById(id); + if (state == null) { + throw new IllegalStateException("No state for ID " + id); + } + return state.toBaseBlock(); + } + + private final Int2IntMap commonMap = new Int2IntOpenHashMap(64, 0.9f); + private final Int2ObjectMap uncommonMap = new Int2ObjectOpenHashMap<>(1, 0.75f); + + { + commonMap.defaultReturnValue(BlockStateIdAccess.invalidId()); + } + + @Override + public int size() { + return commonMap.size() + uncommonMap.size(); + } + + @Override + public ObjectSet> int2ObjectEntrySet() { + return new AbstractObjectSet>() { + @Override + @Nonnull + public ObjectIterator> iterator() { + return new ObjectIterator>() { + + private final ObjectIterator commonIter + = Int2IntMaps.fastIterator(commonMap); + private final ObjectIterator> uncommonIter + = Int2ObjectMaps.fastIterator(uncommonMap); + private boolean lastNextFromCommon = false; + + @Override + public boolean hasNext() { + return commonIter.hasNext() || uncommonIter.hasNext(); + } + + @Override + public Entry next() { + if (commonIter.hasNext()) { + Int2IntMap.Entry e = commonIter.next(); + lastNextFromCommon = true; + return new BasicEntry<>( + e.getIntKey(), assumeAsBlock(e.getIntValue()) + ); + } + if (uncommonIter.hasNext()) { + lastNextFromCommon = false; + return uncommonIter.next(); + } + throw new NoSuchElementException(); + } + + @Override + public void remove() { + if (lastNextFromCommon) { + commonIter.remove(); + } else { + uncommonIter.remove(); + } + } + }; + } + + @Override + public int size() { + return Int2BaseBlockMap.this.size(); + } + }; + } + + @Override + public BaseBlock get(int key) { + int oldId = commonMap.get(key); + if (!BlockStateIdAccess.isValidInternalId(oldId)) { + return uncommonMap.get(key); + } + return assumeAsBlock(oldId); + } + + @Override + public boolean containsKey(int k) { + return commonMap.containsKey(k) || uncommonMap.containsKey(k); + } + + @Override + public boolean containsValue(Object v) { + BaseBlock block = (BaseBlock) v; + int internalId = optimizedInternalId(block); + if (!BlockStateIdAccess.isValidInternalId(internalId)) { + return uncommonMap.containsValue(block); + } + return commonMap.containsValue(internalId); + } + + @Override + public BaseBlock put(int key, BaseBlock value) { + int internalId = optimizedInternalId(value); + if (!BlockStateIdAccess.isValidInternalId(internalId)) { + BaseBlock old = uncommonMap.put(key, value); + if (old == null) { + // ensure common doesn't have the entry too + int oldId = commonMap.remove(key); + return assumeAsBlock(oldId); + } + return old; + } + int oldId = commonMap.put(key, internalId); + return BlockStateIdAccess.isValidInternalId(oldId) ? assumeAsBlock(oldId) : uncommonMap.remove(key); + } + + @Override + public BaseBlock remove(int key) { + int removed = commonMap.remove(key); + if (!BlockStateIdAccess.isValidInternalId(removed)) { + return uncommonMap.remove(key); + } + return assumeAsBlock(removed); + } + + @Override + public void replaceAll(BiFunction function) { + for (ObjectIterator iter = Int2IntMaps.fastIterator(commonMap); + iter.hasNext(); ) { + Int2IntMap.Entry next = iter.next(); + BaseBlock value = function.apply(next.getIntKey(), assumeAsBlock(next.getIntValue())); + int internalId = optimizedInternalId(value); + if (!BlockStateIdAccess.isValidInternalId(internalId)) { + uncommonMap.put(next.getIntKey(), value); + iter.remove(); + } else { + next.setValue(internalId); + } + } + for (ObjectIterator> iter = Int2ObjectMaps.fastIterator(uncommonMap); + iter.hasNext(); ) { + Entry next = iter.next(); + BaseBlock value = function.apply(next.getIntKey(), next.getValue()); + int internalId = optimizedInternalId(value); + if (!BlockStateIdAccess.isValidInternalId(internalId)) { + next.setValue(value); + } else { + commonMap.put(next.getIntKey(), internalId); + iter.remove(); + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java b/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java new file mode 100644 index 0000000..22aa0dc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.collection; + +import com.google.common.collect.Iterators; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.LocatedBlock; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Iterator; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Wrapper around a list of blocks located in the world. + */ +public class LocatedBlockList implements Iterable { + + private final BlockMap blocks = BlockMap.createForBaseBlock(); + private final PositionList order = PositionList.create( + WorldEdit.getInstance().getConfiguration().extendedYLimit + ); + + public LocatedBlockList() { + } + + public LocatedBlockList(Collection collection) { + for (LocatedBlock locatedBlock : collection) { + add(locatedBlock.getLocation(), locatedBlock.getBlock()); + } + } + + public void add(LocatedBlock setBlockCall) { + checkNotNull(setBlockCall); + add(setBlockCall.getLocation(), setBlockCall.getBlock()); + } + + public > void add(BlockVector3 location, B block) { + blocks.put(location, block.toBaseBlock()); + order.add(location); + } + + public boolean containsLocation(BlockVector3 location) { + return blocks.containsKey(location); + } + + public @Nullable BaseBlock get(BlockVector3 location) { + return blocks.get(location); + } + + public int size() { + return order.size(); + } + + public void clear() { + blocks.clear(); + order.clear(); + } + + @Override + public Iterator iterator() { + return Iterators.transform(order.iterator(), position -> + new LocatedBlock(position, blocks.get(position))); + } + + public Iterator reverseIterator() { + return Iterators.transform(order.reverseIterator(), position -> + new LocatedBlock(position, blocks.get(position))); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/collection/LongPositionList.java b/src/main/java/com/sk89q/worldedit/util/collection/LongPositionList.java new file mode 100644 index 0000000..ffb53e2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/collection/LongPositionList.java @@ -0,0 +1,91 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.collection; + +import com.google.common.collect.AbstractIterator; +import com.sk89q.worldedit.math.BlockVector3; +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.longs.LongList; +import it.unimi.dsi.fastutil.longs.LongListIterator; + +import java.util.Iterator; +import java.util.function.Predicate; +import java.util.function.ToLongFunction; + +class LongPositionList implements PositionList { + + private final LongList delegate = new LongArrayList(); + + @Override + public BlockVector3 get(int index) { + return BlockVector3.fromLongPackedForm(delegate.getLong(index)); + } + + @Override + public void add(BlockVector3 vector) { + delegate.add(vector.toLongPackedForm()); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + public Iterator iterator() { + return new PositionIterator(delegate.iterator(), + LongListIterator::hasNext, + LongListIterator::nextLong); + } + + @Override + public Iterator reverseIterator() { + return new PositionIterator(delegate.listIterator(size()), + LongListIterator::hasPrevious, + LongListIterator::previousLong); + } + + private static final class PositionIterator extends AbstractIterator { + + private final LongListIterator iterator; + private final Predicate hasNext; + private final ToLongFunction next; + + private PositionIterator(LongListIterator iterator, + Predicate hasNext, + ToLongFunction next) { + this.iterator = iterator; + this.hasNext = hasNext; + this.next = next; + } + + @Override + protected BlockVector3 computeNext() { + return hasNext.test(iterator) + ? BlockVector3.fromLongPackedForm(next.applyAsLong(iterator)) + : endOfData(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/collection/MoreStreams.java b/src/main/java/com/sk89q/worldedit/util/collection/MoreStreams.java new file mode 100644 index 0000000..a60204b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/collection/MoreStreams.java @@ -0,0 +1,83 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.collection; + +import com.google.common.collect.AbstractIterator; + +import java.util.Iterator; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Predicate; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static java.util.Objects.requireNonNull; + +/** + * Additionally stream facilities. + */ +public class MoreStreams { + + /** + * Emit elements from {@code stream} until {@code predicate} returns {@code false}. + */ + public static Stream takeWhile(Stream stream, Predicate predicate) { + return takeUntil(stream, predicate.negate()); + } + + /** + * Emit elements from {@code stream} until {@code predicate} returns {@code true}. + */ + public static Stream takeUntil(Stream stream, Predicate predicate) { + Spliterator spliterator = stream.spliterator(); + Iterator iter = new AbstractIterator() { + + private Iterator source = Spliterators.iterator(spliterator); + + @Override + protected T computeNext() { + Iterator src = requireNonNull(source); + if (!src.hasNext()) { + return done(); + } + T next = src.next(); + if (predicate.test(next)) { + return done(); + } + return next; + } + + private T done() { + // allow GC of source + source = null; + return endOfData(); + } + }; + int chars = spliterator.characteristics(); + // Not SIZED, Not SUBSIZED + chars &= ~(Spliterator.SIZED | Spliterator.SUBSIZED); + return StreamSupport.stream(Spliterators.spliterator( + iter, spliterator.estimateSize(), chars + ), stream.isParallel()).onClose(stream::close); + } + + private MoreStreams() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/collection/PositionList.java b/src/main/java/com/sk89q/worldedit/util/collection/PositionList.java new file mode 100644 index 0000000..5bada73 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/collection/PositionList.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.collection; + +import com.sk89q.worldedit.math.BlockVector3; + +import java.util.Iterator; + +interface PositionList { + + static PositionList create(boolean extendedYLimit) { + if (extendedYLimit) { + return new VectorPositionList(); + } + return new LongPositionList(); + } + + BlockVector3 get(int index); + + void add(BlockVector3 vector); + + int size(); + + void clear(); + + Iterator iterator(); + + Iterator reverseIterator(); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java b/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java new file mode 100644 index 0000000..9af3018 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java @@ -0,0 +1,105 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.collection; + +import com.google.common.collect.AbstractIterator; +import com.sk89q.worldedit.math.BlockVector3; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntIterator; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.ints.IntListIterator; + +import java.util.Iterator; + +class VectorPositionList implements PositionList { + + private final IntList delegateX = new IntArrayList(); + private final IntList delegateY = new IntArrayList(); + private final IntList delegateZ = new IntArrayList(); + + @Override + public BlockVector3 get(int index) { + return BlockVector3.at( + delegateX.getInt(index), + delegateY.getInt(index), + delegateZ.getInt(index)); + } + + @Override + public void add(BlockVector3 vector) { + delegateX.add(vector.getX()); + delegateY.add(vector.getY()); + delegateZ.add(vector.getZ()); + } + + @Override + public int size() { + return delegateX.size(); + } + + @Override + public void clear() { + delegateX.clear(); + delegateY.clear(); + delegateZ.clear(); + } + + @Override + public Iterator iterator() { + return new AbstractIterator() { + + private final IntIterator iteratorX = delegateX.iterator(); + private final IntIterator iteratorY = delegateY.iterator(); + private final IntIterator iteratorZ = delegateZ.iterator(); + + @Override + protected BlockVector3 computeNext() { + if (!iteratorX.hasNext()) { + return endOfData(); + } + return BlockVector3.at( + iteratorX.nextInt(), + iteratorY.nextInt(), + iteratorZ.nextInt()); + } + }; + } + + @Override + public Iterator reverseIterator() { + return new AbstractIterator() { + + private final IntListIterator iteratorX = delegateX.listIterator(delegateX.size()); + private final IntListIterator iteratorY = delegateY.listIterator(delegateY.size()); + private final IntListIterator iteratorZ = delegateZ.listIterator(delegateZ.size()); + + @Override + protected BlockVector3 computeNext() { + if (!iteratorX.hasPrevious()) { + return endOfData(); + } + return BlockVector3.at( + iteratorX.previousInt(), + iteratorY.previousInt(), + iteratorZ.previousInt()); + } + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/concurrency/EvenMoreExecutors.java b/src/main/java/com/sk89q/worldedit/util/concurrency/EvenMoreExecutors.java new file mode 100644 index 0000000..dfd9a9c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/concurrency/EvenMoreExecutors.java @@ -0,0 +1,74 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.concurrency; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Even more {@code ExecutorService} factory methods. + */ +public final class EvenMoreExecutors { + + private EvenMoreExecutors() { + } + + /** + * Creates a thread pool that creates new threads as needed up to + * a maximum number of threads, but will reuse previously constructed + * threads when they are available. + * + * @param minThreads the minimum number of threads to have at a given time + * @param maxThreads the maximum number of threads to have at a given time + * @param queueSize the size of the queue before new submissions are rejected + * @return the newly created thread pool + */ + public static ExecutorService newBoundedCachedThreadPool(int minThreads, int maxThreads, int queueSize) { + return newBoundedCachedThreadPool(minThreads, maxThreads, queueSize, null); + } + + /** + * Creates a thread pool that creates new threads as needed up to + * a maximum number of threads, but will reuse previously constructed + * threads when they are available. + * + * @param minThreads the minimum number of threads to have at a given time + * @param maxThreads the maximum number of threads to have at a given time + * @param queueSize the size of the queue before new submissions are rejected + * @param threadFormat thread name formatter + * @return the newly created thread pool + */ + public static ExecutorService newBoundedCachedThreadPool(int minThreads, int maxThreads, int queueSize, String threadFormat) { + ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( + minThreads, maxThreads, + 60L, TimeUnit.SECONDS, + new LinkedBlockingDeque<>(queueSize)); + threadPoolExecutor.allowCoreThreadTimeOut(true); + if (threadFormat != null) { + threadPoolExecutor.setThreadFactory(new ThreadFactoryBuilder().setNameFormat(threadFormat).build()); + } + return threadPoolExecutor; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/concurrency/LazyReference.java b/src/main/java/com/sk89q/worldedit/util/concurrency/LazyReference.java new file mode 100644 index 0000000..f755b3f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/concurrency/LazyReference.java @@ -0,0 +1,75 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.concurrency; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; + +/** + * Thread-safe lazy reference. + */ +public class LazyReference { + + public static LazyReference from(Supplier valueComputation) { + return new LazyReference<>(valueComputation); + } + + // Memory saving technique: hold the computation info in the same reference field that we'll + // put the value into, so the memory possibly retained by those parts is GC'able as soon as + // it's no longer needed. + + private static final class RefInfo { + private final Lock lock = new ReentrantLock(); + private final Supplier valueComputation; + + private RefInfo(Supplier valueComputation) { + this.valueComputation = valueComputation; + } + } + + private Object value; + + private LazyReference(Supplier valueComputation) { + this.value = new RefInfo<>(valueComputation); + } + + // casts are safe, value is either RefInfo or T + @SuppressWarnings("unchecked") + public T getValue() { + Object v = value; + if (!(v instanceof RefInfo)) { + return (T) v; + } + RefInfo refInfo = (RefInfo) v; + refInfo.lock.lock(); + try { + v = value; + if (!(v instanceof RefInfo)) { + return (T) v; + } + value = v = refInfo.valueComputation.get(); + return (T) v; + } finally { + refInfo.lock.unlock(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/AnnotatedSubscriberFinder.java b/src/main/java/com/sk89q/worldedit/util/eventbus/AnnotatedSubscriberFinder.java new file mode 100644 index 0000000..92ed8d5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/AnnotatedSubscriberFinder.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.eventbus; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; + +/** + * A {@link SubscriberFindingStrategy} for collecting all event handler methods + * that are marked with the {@link Subscribe} annotation. + * + *

Original for Guava, licensed under the Apache License, Version 2.0.

+ */ +class AnnotatedSubscriberFinder implements SubscriberFindingStrategy { + + /** + * {@inheritDoc} + * + *

+ * This implementation finds all methods marked with a {@link Subscribe} + * annotation. + *

+ */ + @Override + public Multimap, EventHandler> findAllSubscribers(Object listener) { + Multimap, EventHandler> methodsInListener = HashMultimap.create(); + Class clazz = listener.getClass(); + while (clazz != null) { + for (Method method : clazz.getMethods()) { + Subscribe annotation = method.getAnnotation(Subscribe.class); + method.setAccessible(true); + + if (annotation != null) { + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length != 1) { + throw new IllegalArgumentException( + "Method " + method + " has @Subscribe annotation, but requires " + + parameterTypes.length + " arguments. Event handler methods " + + "must require a single argument." + ); + } + Class eventType = parameterTypes[0]; + MethodHandle handle; + try { + handle = MethodHandles.publicLookup().unreflect(method); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException("Method " + method + " failed to unreflect.", e); + } + + EventHandler handler = new MethodHandleEventHandler(annotation.priority(), listener, handle, method.getName()); + methodsInListener.put(eventType, handler); + } + } + clazz = clazz.getSuperclass(); + } + + return methodsInListener; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java b/src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java new file mode 100644 index 0000000..34286db --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java @@ -0,0 +1,199 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.eventbus; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.SetMultimap; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import org.apache.logging.log4j.Logger; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Dispatches events to listeners, and provides ways for listeners to register + * themselves. + * + *

This class is based on Guava's {@link EventBus} but priority is supported + * and events are dispatched at the time of call, rather than being queued up. + * This does allow dispatching during an in-progress dispatch.

+ */ +public final class EventBus { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + + private final SetMultimap, EventHandler> handlersByType = + HashMultimap.create(); + + /** + * Strategy for finding handler methods in registered objects. Currently, + * only the {@link AnnotatedSubscriberFinder} is supported, but this is + * encapsulated for future expansion. + */ + private final SubscriberFindingStrategy finder = new AnnotatedSubscriberFinder(); + + private final HierarchyCache flattenHierarchyCache = new HierarchyCache(); + + /** + * Registers the given handler for the given class to receive events. + * + * @param clazz the event class to register + * @param handler the handler to register + */ + public void subscribe(Class clazz, EventHandler handler) { + checkNotNull(clazz); + checkNotNull(handler); + lock.writeLock().lock(); + try { + handlersByType.put(clazz, handler); + } finally { + lock.writeLock().unlock(); + } + } + + /** + * Registers the given handler for the given class to receive events. + * + * @param handlers a map of handlers + */ + public void subscribeAll(Multimap, EventHandler> handlers) { + checkNotNull(handlers); + lock.writeLock().lock(); + try { + handlersByType.putAll(handlers); + } finally { + lock.writeLock().unlock(); + } + } + + /** + * Unregisters the given handler for the given class. + * + * @param clazz the class + * @param handler the handler + */ + public void unsubscribe(Class clazz, EventHandler handler) { + checkNotNull(clazz); + checkNotNull(handler); + lock.writeLock().lock(); + try { + handlersByType.remove(clazz, handler); + } finally { + lock.writeLock().unlock(); + } + } + + /** + * Unregisters the given handlers. + * + * @param handlers a map of handlers + */ + public void unsubscribeAll(Multimap, EventHandler> handlers) { + checkNotNull(handlers); + lock.writeLock().lock(); + try { + for (Map.Entry, Collection> entry : handlers.asMap().entrySet()) { + handlersByType.get(entry.getKey()).removeAll(entry.getValue()); + } + } finally { + lock.writeLock().unlock(); + } + } + + /** + * Registers all handler methods on {@code object} to receive events. + * Handler methods are selected and classified using this EventBus's + * {@link SubscriberFindingStrategy}; the default strategy is the + * {@link AnnotatedSubscriberFinder}. + * + * @param object object whose handler methods should be registered. + */ + public void register(Object object) { + subscribeAll(finder.findAllSubscribers(object)); + } + + /** + * Unregisters all handler methods on a registered {@code object}. + * + * @param object object whose handler methods should be unregistered. + * @throws IllegalArgumentException if the object was not previously registered. + */ + public void unregister(Object object) { + unsubscribeAll(finder.findAllSubscribers(object)); + } + + /** + * Posts an event to all registered handlers. This method will return + * successfully after the event has been posted to all handlers, and + * regardless of any exceptions thrown by handlers. + * + * @param event event to post. + */ + public void post(Object event) { + List dispatching = new ArrayList<>(); + + Set> dispatchTypes = flattenHierarchyCache.get(event.getClass()); + lock.readLock().lock(); + try { + for (Class eventType : dispatchTypes) { + Set wrappers = handlersByType.get(eventType); + + if (wrappers != null && !wrappers.isEmpty()) { + dispatching.addAll(wrappers); + } + } + } finally { + lock.readLock().unlock(); + } + + Collections.sort(dispatching); + + for (EventHandler handler : dispatching) { + dispatch(event, handler); + } + } + + /** + * Dispatches {@code event} to the handler in {@code handler}. + * + * @param event event to dispatch. + * @param handler handler that will call the handler. + */ + private void dispatch(Object event, EventHandler handler) { + try { + handler.handleEvent(event); + } catch (InvocationTargetException e) { + LOGGER.error("Could not dispatch event: " + event + " to handler " + handler, e); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/EventHandler.java b/src/main/java/com/sk89q/worldedit/util/eventbus/EventHandler.java new file mode 100644 index 0000000..1cfad26 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/EventHandler.java @@ -0,0 +1,105 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.eventbus; + +import java.lang.reflect.InvocationTargetException; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Event handler object for {@link EventBus} that is able to dispatch + * an event. + * + *

Original for Guava, licensed under the Apache License, Version 2.0.

+ */ +public abstract class EventHandler implements Comparable { + + public enum Priority { + VERY_EARLY, + EARLY, + NORMAL, + LATE, + VERY_LATE + } + + private final Priority priority; + + /** + * Create a new event handler. + * + * @param priority the priority + */ + protected EventHandler(Priority priority) { + checkNotNull(priority); + this.priority = priority; + } + + /** + * Get the priority. + * + * @return the priority + */ + public Priority getPriority() { + return priority; + } + + /** + * Dispatch the given event. + * + *

Subclasses should override {@link #dispatch(Object)}.

+ * + * @param event the event + * @throws InvocationTargetException thrown if an exception is thrown during dispatch + */ + public final void handleEvent(Object event) throws InvocationTargetException { + try { + dispatch(event); + } catch (Throwable t) { + throw new InvocationTargetException(t); + } + } + + /** + * Dispatch the event. + * + * @param event the event object + * @throws Exception an exception that may be thrown + */ + public abstract void dispatch(Object event) throws Exception; + + @Override + public int compareTo(EventHandler o) { + return getPriority().ordinal() - o.getPriority().ordinal(); + } + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(Object obj); + + @Override + public String toString() { + return "EventHandler{" + + "priority=" + priority + + '}'; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/HierarchyCache.java b/src/main/java/com/sk89q/worldedit/util/eventbus/HierarchyCache.java new file mode 100644 index 0000000..92d35af --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/HierarchyCache.java @@ -0,0 +1,66 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.eventbus; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * Holds a cache of class hierarchy. + */ +class HierarchyCache { + + private final LoadingCache, Set>> cache = CacheBuilder.newBuilder() + .weakKeys() + .build(CacheLoader.from(this::build)); + + public Set> get(Class concreteClass) { + return cache.getUnchecked(concreteClass); + } + + protected Set> build(Class concreteClass) { + List> parents = Lists.newLinkedList(); + Set> classes = Sets.newHashSet(); + + parents.add(concreteClass); + + while (!parents.isEmpty()) { + Class clazz = parents.remove(0); + classes.add(clazz); + + Class parent = clazz.getSuperclass(); + if (parent != null) { + parents.add(parent); + } + + Collections.addAll(parents, clazz.getInterfaces()); + } + + return classes; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/MethodEventHandler.java b/src/main/java/com/sk89q/worldedit/util/eventbus/MethodEventHandler.java new file mode 100644 index 0000000..0353103 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/MethodEventHandler.java @@ -0,0 +1,86 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.eventbus; + +import java.lang.reflect.Method; +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Invokes a {@link Method} to dispatch an event. + */ +public class MethodEventHandler extends EventHandler { + + private final Object object; + private final Method method; + + /** + * Create a new event handler. + * + * @param priority the priority + * @param method the method + */ + public MethodEventHandler(Priority priority, Object object, Method method) { + super(priority); + checkNotNull(method); + this.object = object; + this.method = method; + } + + /** + * Get the method. + * + * @return the method + */ + public Method getMethod() { + return method; + } + + @Override + public void dispatch(Object event) throws Exception { + method.invoke(object, event); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + MethodEventHandler that = (MethodEventHandler) o; + + if (!method.equals(that.method)) { + return false; + } + + return Objects.equals(object, that.object); + } + + @Override + public int hashCode() { + int result = object != null ? object.hashCode() : 0; + result = 31 * result + method.hashCode(); + return result; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/MethodHandleEventHandler.java b/src/main/java/com/sk89q/worldedit/util/eventbus/MethodHandleEventHandler.java new file mode 100644 index 0000000..33ca1d3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/MethodHandleEventHandler.java @@ -0,0 +1,82 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.eventbus; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.Objects; + +public class MethodHandleEventHandler extends EventHandler { + + private final MethodHandle methodHandle; + private final String methodName; + private final Object object; + + /** + * Create a new event handler that uses MethodHandles to dispatch. + * + * @param priority the priority + * @param object The object to invoke it on + * @param methodHandle The handle to invoke + * @param methodName The name of the method (for equality checks) + */ + protected MethodHandleEventHandler(Priority priority, Object object, MethodHandle methodHandle, String methodName) { + super(priority); + + this.object = object; + this.methodHandle = methodHandle.bindTo(object).asType(MethodType.methodType(void.class, Object.class)); + this.methodName = methodName; + } + + @Override + public void dispatch(Object event) throws Exception { + try { + this.methodHandle.invokeExact(event); + } catch (Exception | Error e) { + throw e; + } catch (Throwable t) { + // If it's not an Exception or Error, throw it wrapped. + throw new Exception(t); + } + } + + @Override + public int hashCode() { + return Objects.hash(methodName, object); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + MethodHandleEventHandler that = (MethodHandleEventHandler) o; + + if (!methodName.equals(that.methodName)) { + return false; + } + + return Objects.equals(object, that.object); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/Subscribe.java b/src/main/java/com/sk89q/worldedit/util/eventbus/Subscribe.java new file mode 100644 index 0000000..044e4fa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/Subscribe.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.eventbus; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Used to mark methods as event handlers. + */ +@Retention(RUNTIME) +@Target(METHOD) +public @interface Subscribe { + + /** + * The priority as far as order of dispatching is concerned. + * + * @return the priority + */ + EventHandler.Priority priority() default EventHandler.Priority.NORMAL; + +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/SubscriberFindingStrategy.java b/src/main/java/com/sk89q/worldedit/util/eventbus/SubscriberFindingStrategy.java new file mode 100644 index 0000000..e4339f6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/SubscriberFindingStrategy.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.eventbus; + +import com.google.common.collect.Multimap; + +/** + * A method for finding event handler methods in objects, for use by + * {@link EventBus}. + */ +interface SubscriberFindingStrategy { + + /** + * Finds all suitable event handler methods in {@code source}, organizes them + * by the type of event they handle, and wraps them in {@link EventHandler}s. + * + * @param source object whose handlers are desired. + * @return EventHandler objects for each handler method, organized by event + * type. + * + * @throws IllegalArgumentException if {@code source} is not appropriate for + * this strategy (in ways that this interface does not define). + */ + Multimap, EventHandler> findAllSubscribers(Object source); + +} \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/WorldEditText.java b/src/main/java/com/sk89q/worldedit/util/formatting/WorldEditText.java new file mode 100644 index 0000000..4f06e10 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/WorldEditText.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting; + +import com.sk89q.worldedit.WorldEdit; +import net.kyori.text.Component; +import org.enginehub.piston.config.ConfigHolder; +import org.enginehub.piston.config.ConfigRenderer; +import org.enginehub.piston.config.TextConfig; +import org.enginehub.piston.util.TextHelper; + +import java.util.Locale; + +public class WorldEditText { + private static final ConfigRenderer RENDERER = ConfigRenderer.getInstance(); + public static final ConfigHolder CONFIG_HOLDER = ConfigHolder.create(); + + static { + CONFIG_HOLDER.getConfig(TextConfig.commandPrefix()).setValue("/"); + } + + public static Component format(Component component, Locale locale) { + return WorldEdit.getInstance().getTranslationManager().convertText( + RENDERER.render(component, CONFIG_HOLDER), + locale + ); + } + + public static String reduceToText(Component component, Locale locale) { + return TextHelper.reduceToText(format(component, locale)); + } + + private WorldEditText() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java new file mode 100644 index 0000000..dd78823 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java @@ -0,0 +1,48 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; + +/** + * Represents a fragment representing a command that is to be typed. + */ +public class CodeFormat extends TextComponentProducer { + + private CodeFormat() { + getBuilder().content("").color(TextColor.AQUA); + } + + /** + * Creates a CodeFormat with the given message. + * + * @param texts The text + * @return The Component + */ + public static TextComponent wrap(String... texts) { + CodeFormat code = new CodeFormat(); + for (String text: texts) { + code.append(text); + } + + return code.create(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java new file mode 100644 index 0000000..852b872 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -0,0 +1,107 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import com.google.common.collect.Lists; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.format.TextColor; + +import java.util.List; + +public class CommandListBox extends PaginationBox { + + private final List commands = Lists.newArrayList(); + private final String helpCommand; + private boolean hideHelp; + + /** + * Create a new box. + * + * @param title the title + */ + public CommandListBox(String title, String pageCommand, String helpCommand) { + super(title, pageCommand); + this.helpCommand = helpCommand; + } + + @Override + public Component getComponent(int number) { + return commands.get(number).createComponent(hideHelp); + } + + @Override + public int getComponentsSize() { + return commands.size(); + } + + public void appendCommand(String alias, Component description) { + appendCommand(alias, description, null); + } + + @Deprecated + public void appendCommand(String alias, String description, String insertion) { + appendCommand(alias, TextComponent.of(description), insertion); + } + + public void appendCommand(String alias, Component description, String insertion) { + commands.add(new CommandEntry(alias, description, insertion)); + } + + public boolean isHidingHelp() { + return hideHelp; + } + + public void setHidingHelp(boolean hideHelp) { + this.hideHelp = hideHelp; + } + + private class CommandEntry { + private final String alias; + private final Component description; + private final String insertion; + + CommandEntry(String alias, Component description, String insertion) { + this.alias = alias; + this.description = description; + this.insertion = insertion; + } + + Component createComponent(boolean hideHelp) { + TextComponentProducer line = new TextComponentProducer(); + if (!hideHelp) { + line.append(SubtleFormat.wrap("? ") + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, CommandListBox.this.helpCommand + " " + insertion)) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help")))); + } + TextComponent command = TextComponent.of(alias, TextColor.GOLD); + if (insertion == null) { + line.append(command); + } else { + line.append(command + .clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, insertion)) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select")))); + } + return line.append(TextComponent.of(": ")).append(description).create(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java new file mode 100644 index 0000000..c89dd70 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -0,0 +1,89 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import com.google.common.collect.Iterables; +import net.kyori.text.TextComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.format.TextDecoration; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.config.ColorConfig; +import org.enginehub.piston.util.HelpGenerator; + +import javax.annotation.Nullable; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.internal.command.CommandUtil.getSubCommands; + +/** + * A box to describe usage of a command. + */ +public class CommandUsageBox extends TextComponentProducer { + + /** + * Create a new usage box. + * + * @param commands the commands to describe + * @param commandString the commands that were used, such as "/we" or "/brush sphere" + * @param helpRootCommand the command used to get subcommand help + */ + public CommandUsageBox(List commands, String commandString, String helpRootCommand) throws InvalidComponentException { + this(commands, commandString, helpRootCommand, null); + } + + /** + * Create a new usage box. + * + * @param commands the commands to describe + * @param commandString the commands that were used, such as "/we" or "/brush sphere" + * @param helpRootCommand the command used to get subcommand help + * @param parameters list of parameters to use + */ + public CommandUsageBox(List commands, String commandString, String helpRootCommand, + @Nullable CommandParameters parameters) throws InvalidComponentException { + checkNotNull(commands); + checkNotNull(commandString); + checkNotNull(helpRootCommand); + attachCommandUsage(commands, commandString, helpRootCommand); + } + + private void attachCommandUsage(List commands, String commandString, String helpRootCommand) { + TextComponentProducer boxContent = new TextComponentProducer() + .append(HelpGenerator.create(commands).getFullHelp()); + if (getSubCommands(Iterables.getLast(commands)).size() > 0) { + boxContent.append(TextComponent.newline()) + .append(ColorConfig.helpText().wrap(TextComponent.builder("> ") + .append(ColorConfig.mainText().wrap(TextComponent.builder("List Subcommands") + .decoration(TextDecoration.ITALIC, true) + .clickEvent(ClickEvent.runCommand(helpRootCommand + " -s " + commandString)) + .hoverEvent(HoverEvent.showText(TextComponent.of("List all subcommands of this command"))) + .build())) + .build())); + } + MessageBox box = new MessageBox("Help for " + commandString, + boxContent); + + append(box.create()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java new file mode 100644 index 0000000..250224d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java @@ -0,0 +1,51 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; + +/** + * Represents a fragment representing an error. + */ +public class ErrorFormat extends TextComponentProducer { + + /** + * Create a new instance. + */ + private ErrorFormat() { + getBuilder().content("").color(TextColor.RED); + } + + /** + * Creates an ErrorFormat with the given message. + * + * @param texts The text + * @return The Component + */ + public static TextComponent wrap(String... texts) { + ErrorFormat error = new ErrorFormat(); + for (String component : texts) { + error.append(component); + } + + return error.create(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/InvalidComponentException.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/InvalidComponentException.java new file mode 100644 index 0000000..c0e312c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/InvalidComponentException.java @@ -0,0 +1,35 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.Component; + +public class InvalidComponentException extends WorldEditException { + + @Deprecated + public InvalidComponentException(String message) { + super(message); + } + + public InvalidComponentException(Component message) { + super(message); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java new file mode 100644 index 0000000..77fd7cd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java @@ -0,0 +1,51 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; + +/** + * Represents a fragment representing a label. + */ +public class LabelFormat extends TextComponentProducer { + + /** + * Create a new instance. + */ + private LabelFormat() { + getBuilder().content("").color(TextColor.YELLOW); + } + + /** + * Creates a LabelFormat with the given message. + * + * @param texts The text + * @return The Component + */ + public static TextComponent wrap(String... texts) { + LabelFormat label = new LabelFormat(); + for (String component : texts) { + label.append(component); + } + + return label.create(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java new file mode 100644 index 0000000..7d9262b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java @@ -0,0 +1,103 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import com.google.common.base.Strings; +import com.google.common.collect.Sets; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; +import net.kyori.text.format.TextDecoration; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Makes for a box with a border above and below. + */ +public class MessageBox extends TextComponentProducer { + + private static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 47; + + private final TextComponentProducer contents; + private final TextColor borderColor; + + /** + * Create a new box. + */ + public MessageBox(String title, TextComponentProducer contents) { + this(title, contents, TextColor.YELLOW); + } + + /** + * Create a new box. + */ + public MessageBox(String title, TextComponentProducer contents, TextColor borderColor) { + checkNotNull(title); + + this.borderColor = borderColor; + append(centerAndBorder(TextComponent.of(title))).newline(); + this.contents = contents; + } + + protected Component centerAndBorder(TextComponent text) { + TextComponentProducer line = new TextComponentProducer(); + int leftOver = GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH - getLength(text); + int side = (int) Math.floor(leftOver / 2.0); + if (side > 0) { + if (side > 1) { + line.append(createBorder(side - 1)); + } + line.append(TextComponent.space()); + } + line.append(text); + if (side > 0) { + line.append(TextComponent.space()); + if (side > 1) { + line.append(createBorder(side - 1)); + } + } + return line.create(); + } + + private static int getLength(TextComponent text) { + return text.content().length() + text.children().stream().filter(c -> c instanceof TextComponent) + .mapToInt(c -> getLength((TextComponent) c)).sum(); + } + + private TextComponent createBorder(int count) { + return TextComponent.of(Strings.repeat("-", count), + borderColor, Sets.newHashSet(TextDecoration.STRIKETHROUGH)); + } + + /** + * Gets the message box contents producer. + * + * @return The contents producer + */ + public TextComponentProducer getContents() { + return contents; + } + + @Override + public TextComponent create() { + append(contents.create()); + return super.create(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java new file mode 100644 index 0000000..e772215 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java @@ -0,0 +1,161 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.format.TextColor; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.stream.Collectors; + +public abstract class PaginationBox extends MessageBox { + + private static final int IDEAL_ROWS_FOR_PLAYER = 8; + + private String pageCommand; + private int componentsPerPage = IDEAL_ROWS_FOR_PLAYER; + private int currentPage = -1; + + /** + * Creates a Paginated component. + * + * @param title The title + */ + protected PaginationBox(String title) { + this(title, null); + } + + public abstract Component getComponent(int number); + + public abstract int getComponentsSize(); + + public void setComponentsPerPage(int componentsPerPage) { + this.componentsPerPage = componentsPerPage; + } + + public void formatForConsole() { + this.pageCommand = null; + this.componentsPerPage = 20; + } + + protected final int getCurrentPage() { + return currentPage; + } + + /** + * Creates a Paginated component. + * + * @param title The title + * @param pageCommand The command to run to switch page, with %page% representing page number + */ + protected PaginationBox(String title, @Nullable String pageCommand) { + super(title, new TextComponentProducer()); + + if (pageCommand != null && !pageCommand.contains("%page%")) { + throw new IllegalArgumentException("pageCommand must contain %page% if provided."); + } + this.pageCommand = pageCommand; + } + + public Component create(int page) throws InvalidComponentException { + if (page == 1 && getComponentsSize() == 0) { + return getContents().reset().append("No results found.").create(); + } + int pageCount = (int) Math.ceil(getComponentsSize() / (double) componentsPerPage); + if (page < 1 || page > pageCount) { + throw new InvalidComponentException(TranslatableComponent.of("worldedit.error.invalid-page")); + } + currentPage = page; + final int lastComp = Math.min(page * componentsPerPage, getComponentsSize()); + for (int i = (page - 1) * componentsPerPage; i < lastComp; i++) { + getContents().append(getComponent(i)); + if (i + 1 != lastComp) { + getContents().newline(); + } + } + if (pageCount == 1) { + return super.create(); + } + getContents().newline(); + TextComponent pageNumberComponent = TextComponent.of("Page ", TextColor.YELLOW) + .append(TextComponent.of(String.valueOf(page), TextColor.GOLD)) + .append(TextComponent.of(" of ")) + .append(TextComponent.of(String.valueOf(pageCount), TextColor.GOLD)); + if (pageCommand != null) { + TextComponentProducer navProducer = new TextComponentProducer(); + if (page > 1) { + TextComponent prevComponent = TextComponent.of("<<< ", TextColor.GOLD) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page - 1)))) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate"))); + navProducer.append(prevComponent); + } + navProducer.append(pageNumberComponent); + if (page < pageCount) { + TextComponent nextComponent = TextComponent.of(" >>>", TextColor.GOLD) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page + 1)))) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate"))); + navProducer.append(nextComponent); + } + getContents().append(centerAndBorder(navProducer.create())); + } else { + getContents().append(centerAndBorder(pageNumberComponent)); + } + return super.create(); + } + + @Override + public TextComponent create() { + throw new IllegalStateException("Pagination components must be created with a page"); + } + + public static PaginationBox fromStrings(String header, @Nullable String pageCommand, List lines) { + return fromComponents(header, pageCommand, lines.stream() + .map(TextComponent::of) + .collect(Collectors.toList())); + } + + public static PaginationBox fromComponents(String header, @Nullable String pageCommand, List lines) { + return new ListPaginationBox(header, pageCommand, lines); + } + + private static class ListPaginationBox extends PaginationBox { + private final List lines; + + ListPaginationBox(String header, String pageCommand, List lines) { + super(header, pageCommand); + this.lines = lines; + } + + @Override + public Component getComponent(int number) { + return lines.get(number); + } + + @Override + public int getComponentsSize() { + return lines.size(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/SideEffectBox.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/SideEffectBox.java new file mode 100644 index 0000000..1fffcc8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/SideEffectBox.java @@ -0,0 +1,93 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.formatting.WorldEditText; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.format.TextColor; + +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +public class SideEffectBox extends PaginationBox { + + private static final LazyReference> SIDE_EFFECTS = LazyReference.from(() -> + WorldEdit.getInstance().getPlatformManager().getSupportedSideEffects() + .stream() + .sorted(Comparator.comparing(effect -> + WorldEditText.reduceToText( + TranslatableComponent.of(effect.getDisplayName()), + Locale.US + ) + )) + .collect(Collectors.toList()) + ); + + private final SideEffectSet sideEffectSet; + + private static List getSideEffects() { + return SIDE_EFFECTS.getValue(); + } + + public SideEffectBox(SideEffectSet sideEffectSet) { + super("Side Effects"); + + this.sideEffectSet = sideEffectSet; + } + + private static final SideEffect.State[] SHOWN_VALUES = {SideEffect.State.OFF, SideEffect.State.ON}; + + @Override + public Component getComponent(int number) { + SideEffect effect = getSideEffects().get(number); + SideEffect.State state = this.sideEffectSet.getState(effect); + + TextComponent.Builder builder = TextComponent.builder(); + builder = builder.append(TranslatableComponent.of(effect.getDisplayName(), TextColor.YELLOW) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TranslatableComponent.of(effect.getDescription())))); + for (SideEffect.State uiState : SHOWN_VALUES) { + builder = builder.append(TextComponent.space()); + builder = builder.append(TranslatableComponent.of(uiState.getDisplayName(), uiState == state ? TextColor.WHITE : TextColor.GRAY) + .clickEvent(ClickEvent.runCommand("//perf -h " + effect.name().toLowerCase(Locale.US) + " " + uiState.name().toLowerCase(Locale.US))) + .hoverEvent(HoverEvent.showText(uiState == state + ? TranslatableComponent.of("worldedit.sideeffect.box.current") + : TranslatableComponent.of("worldedit.sideeffect.box.change-to", TranslatableComponent.of(uiState.getDisplayName())) + )) + ); + } + + return builder.build(); + } + + @Override + public int getComponentsSize() { + return getSideEffects().size(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java new file mode 100644 index 0000000..b75aff3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java @@ -0,0 +1,51 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; + +/** + * Represents a subtle part of the message. + */ +public class SubtleFormat extends TextComponentProducer { + + /** + * Create a new instance. + */ + private SubtleFormat() { + getBuilder().content("").color(TextColor.GRAY); + } + + /** + * Creates a SubtleFormat with the given message. + * + * @param texts The text + * @return The Component + */ + public static TextComponent wrap(String... texts) { + SubtleFormat subtle = new SubtleFormat(); + for (String component : texts) { + subtle.append(component); + } + + return subtle.create(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java new file mode 100644 index 0000000..c7dbbeb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java @@ -0,0 +1,83 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import net.kyori.text.Component; +import net.kyori.text.TextComponent; + +public class TextComponentProducer { + + private TextComponent.Builder builder = TextComponent.builder().content(""); + + public TextComponent.Builder getBuilder() { + return builder; + } + + /** + * Adds a component as a child to this Producer. + * + * @param component The component + * @return The producer, for chaining + */ + public TextComponentProducer append(Component component) { + getBuilder().append(component); + return this; + } + + /** + * Adds a string as a child to this Producer. + * + * @param string The text + * @return The producer, for chaining + */ + public TextComponentProducer append(String string) { + getBuilder().append(TextComponent.of(string)); + return this; + } + + /** + * Adds a newline as a child to this Producer. + * + * @return The producer, for chaining + */ + public TextComponentProducer newline() { + getBuilder().append(TextComponent.newline()); + return this; + } + + /** + * Create a TextComponent from this producer. + * + * @return The component + */ + public TextComponent create() { + return builder.build(); + } + + /** + * Reset the producer to a clean slate. + * + * @return The producer, for chaining + */ + public TextComponentProducer reset() { + builder = TextComponent.builder().content(""); + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/formatting/component/TextUtils.java b/src/main/java/com/sk89q/worldedit/util/formatting/component/TextUtils.java new file mode 100644 index 0000000..def39cf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/formatting/component/TextUtils.java @@ -0,0 +1,63 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.formatting.component; + +import net.kyori.text.Component; +import net.kyori.text.TextComponent; + +import java.util.List; +import java.util.Locale; + +public class TextUtils { + + private TextUtils() { + } + + /** + * Join an array of components with a joiner component. + * + * @param components The components to join + * @param joiner The joiner component + * @return The joined component + */ + public static Component join(List components, Component joiner) { + TextComponent.Builder builder = TextComponent.builder(); + for (int i = 0; i < components.size(); i++) { + builder.append(components.get(i)); + if (i < components.size() - 1) { + builder.append(joiner); + } + } + return builder.build(); + } + + /** + * Gets a Java Locale object by the Minecraft locale tag. + * + * @param locale The Minecraft locale tag + * @return A Java locale + */ + public static Locale getLocaleByMinecraftTag(String locale) { + if (locale == null) { + return Locale.US; + } + return Locale.forLanguageTag(locale.replace('_', '-')); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/function/IOFunction.java b/src/main/java/com/sk89q/worldedit/util/function/IOFunction.java new file mode 100644 index 0000000..d92e1fd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/function/IOFunction.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.function; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.function.Function; + +/** + * I/O function type. + */ +@FunctionalInterface +public interface IOFunction { + + static Function unchecked(IOFunction function) { + return param -> { + try { + return function.apply(param); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }; + } + + R apply(T param) throws IOException; + +} diff --git a/src/main/java/com/sk89q/worldedit/util/function/IORunnable.java b/src/main/java/com/sk89q/worldedit/util/function/IORunnable.java new file mode 100644 index 0000000..09c7ccc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/function/IORunnable.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.function; + +import java.io.IOException; +import java.io.UncheckedIOException; + +/** + * I/O runnable type. + */ +@FunctionalInterface +public interface IORunnable { + + static Runnable unchecked(IORunnable runnable) { + return () -> { + try { + runnable.run(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }; + } + + void run() throws IOException; + +} diff --git a/src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java b/src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java new file mode 100644 index 0000000..ddb0eb1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java @@ -0,0 +1,193 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.function; + +import com.google.common.base.Function; + +import javax.annotation.Nullable; +import java.util.Locale; +import java.util.regex.Pattern; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Provides a Levenshtein distance between a given string and each string + * that this function is applied to. + */ +public class LevenshteinDistance implements Function { + + public static final Pattern STANDARD_CHARS = Pattern.compile("[ _\\-]"); + + private final String baseString; + private final boolean caseSensitive; + private final Pattern replacePattern; + + /** + * Create a new instance. + * + * @param baseString the string to compare to + * @param caseSensitive true to make case sensitive comparisons + */ + public LevenshteinDistance(String baseString, boolean caseSensitive) { + this(baseString, caseSensitive, null); + } + + /** + * Create a new instance. + * + * @param baseString the string to compare to + * @param caseSensitive true to make case sensitive comparisons + * @param replacePattern pattern to match characters to be removed in both the input and test strings (may be null) + */ + public LevenshteinDistance(String baseString, boolean caseSensitive, @Nullable Pattern replacePattern) { + checkNotNull(baseString); + this.caseSensitive = caseSensitive; + this.replacePattern = replacePattern; + baseString = caseSensitive ? baseString : baseString.toLowerCase(Locale.ROOT); + baseString = replacePattern != null ? replacePattern.matcher(baseString).replaceAll("") : baseString; + this.baseString = baseString; + } + + @Nullable + @Override + public Integer apply(String input) { + if (input == null) { + return null; + } + + if (replacePattern != null) { + input = replacePattern.matcher(input).replaceAll(""); + } + + if (caseSensitive) { + return distance(baseString, input); + } else { + return distance(baseString, input.toLowerCase(Locale.ROOT)); + } + } + + /** + *

Find the Levenshtein distance between two Strings.

+ * + *

This is the number of changes needed to change one String into + * another, where each change is a single character modification (deletion, + * insertion or substitution).

+ * + *
+ * + *

Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError + * which can occur when my Java implementation is used with very large strings.
+ * This implementation of the Levenshtein distance algorithm + * is from http://www.merriampark.com/ldjava.htm

+ * + *
+     * distance(null, *)             = IllegalArgumentException
+     * distance(*, null)             = IllegalArgumentException
+     * distance("","")               = 0
+     * distance("","a")              = 1
+     * distance("aaapppp", "")       = 7
+     * distance("frog", "fog")       = 1
+     * distance("fly", "ant")        = 3
+     * distance("elephant", "hippo") = 7
+     * distance("hippo", "elephant") = 7
+     * distance("hippo", "zzzzzzzz") = 8
+     * distance("hello", "hallo")    = 1
+     * 
+ * + * @param s the first String, must not be null + * @param t the second String, must not be null + * @return result distance + * @throws IllegalArgumentException if either String input {@code null} + */ + public static int distance(String s, String t) { + if (s == null || t == null) { + throw new IllegalArgumentException("Strings must not be null"); + } + + /* + * The difference between this impl. and the previous is that, rather + * than creating and retaining a matrix of size s.length()+1 by + * t.length()+1, we maintain two single-dimensional arrays of length + * s.length()+1. The first, d, is the 'current working' distance array + * that maintains the newest distance cost counts as we iterate through + * the characters of String s. Each time we increment the index of + * String t we are comparing, d is copied to p, the second int[]. Doing + * so allows us to retain the previous cost counts as required by the + * algorithm (taking the minimum of the cost count to the left, up one, + * and diagonally up and to the left of the current cost count being + * calculated). (Note that the arrays aren't really copied anymore, just + * switched...this is clearly much better than cloning an array or doing + * a System.arraycopy() each time through the outer loop.) + * + * Effectively, the difference between the two implementations is this + * one does not cause an out of memory condition when calculating the LD + * over two very large strings. + */ + + int n = s.length(); // length of s + int m = t.length(); // length of t + + if (n == 0) { + return m; + } else if (m == 0) { + return n; + } + + int[] p = new int[n + 1]; // 'previous' cost array, horizontally + int[] d = new int[n + 1]; // cost array, horizontally + int[] _d; // placeholder to assist in swapping p and d + + // indexes into strings s and t + int i; // iterates through s + int j; // iterates through t + + char tj; // jth character of t + + int cost; // cost + + for (i = 0; i <= n; ++i) { + p[i] = i; + } + + for (j = 1; j <= m; ++j) { + tj = t.charAt(j - 1); + d[0] = j; + + for (i = 1; i <= n; ++i) { + cost = s.charAt(i - 1) == tj ? 0 : 1; + // minimum of cell to the left+1, to the top+1, diagonally left + // and up +cost + d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + + cost); + } + + // copy current distance counts to 'previous row' distance counts + _d = p; + p = d; + d = _d; + } + + // our last action in the above loop was to switch d and p, so p now + // actually has the most recent cost counts + return p[n]; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/gson/BlockVectorAdapter.java b/src/main/java/com/sk89q/worldedit/util/gson/BlockVectorAdapter.java new file mode 100644 index 0000000..e50e2cb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/gson/BlockVectorAdapter.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.gson; + +import com.google.gson.*; +import com.sk89q.worldedit.math.BlockVector3; + +import java.lang.reflect.Type; + +public class BlockVectorAdapter implements JsonDeserializer { + + @Override + public BlockVector3 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonArray jsonArray = json.getAsJsonArray(); + if (jsonArray.size() != 3) { + throw new JsonParseException("Expected array of 3 length for BlockVector3"); + } + + double x = jsonArray.get(0).getAsInt(); + double y = jsonArray.get(1).getAsInt(); + double z = jsonArray.get(2).getAsInt(); + + return BlockVector3.at(x, y, z); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java b/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java new file mode 100644 index 0000000..d449b5c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.gson; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; + +/** + * Utility methods for Google's GSON library. + */ +public final class GsonUtil { + + private GsonUtil() { + } + + /** + * Create a standard {@link GsonBuilder} for WorldEdit. + * + * @return a builder + */ + public static GsonBuilder createBuilder() { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); + gsonBuilder.registerTypeAdapter(BlockVector3.class, new BlockVectorAdapter()); + return gsonBuilder; + } + + private static final Gson gson = new Gson(); + + public static String stringValue(String s) { + return gson.toJson(s); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/gson/VectorAdapter.java b/src/main/java/com/sk89q/worldedit/util/gson/VectorAdapter.java new file mode 100644 index 0000000..f402745 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/gson/VectorAdapter.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.gson; + +import com.google.gson.*; +import com.sk89q.worldedit.math.Vector3; + +import java.lang.reflect.Type; + +/** + * Deserializes {@code Vector3}s for GSON. + */ +public class VectorAdapter implements JsonDeserializer { + + @Override + public Vector3 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonArray jsonArray = json.getAsJsonArray(); + if (jsonArray.size() != 3) { + throw new JsonParseException("Expected array of 3 length for Vector3"); + } + + double x = jsonArray.get(0).getAsDouble(); + double y = jsonArray.get(1).getAsDouble(); + double z = jsonArray.get(2).getAsDouble(); + + return Vector3.at(x, y, z); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/Closer.java b/src/main/java/com/sk89q/worldedit/util/io/Closer.java new file mode 100644 index 0000000..b9600ca --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/Closer.java @@ -0,0 +1,282 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Throwables; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import org.apache.logging.log4j.Logger; + +import java.io.Closeable; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.zip.ZipFile; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class Closer implements Closeable { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + /** + * The suppressor implementation to use for the current Java version. + */ + private static final Suppressor SUPPRESSOR = SuppressingSuppressor.isAvailable() + ? SuppressingSuppressor.INSTANCE + : LoggingSuppressor.INSTANCE; + + /** + * Creates a new {@link Closer}. + */ + public static Closer create() { + return new Closer(SUPPRESSOR); + } + + @VisibleForTesting + final Suppressor suppressor; + + // only need space for 2 elements in most cases, so try to use the smallest array possible + private final Deque stack = new ArrayDeque<>(4); + private final Deque zipStack = new ArrayDeque<>(4); + private Throwable thrown; + + @VisibleForTesting Closer(Suppressor suppressor) { + this.suppressor = checkNotNull(suppressor); // checkNotNull to satisfy null tests + } + + /** + * Registers the given {@code closeable} to be closed when this {@code Closer} is + * {@linkplain #close closed}. + * + * @return the given {@code closeable} + */ + // close. this word no longer has any meaning to me. + public C register(C closeable) { + stack.push(closeable); + return closeable; + } + + /** + * Registers the given {@code zipFile} to be closed when this {@code Closer} is + * {@linkplain #close closed}. + * + * @return the given {@code closeable} + */ + public Z register(Z zipFile) { + zipStack.push(zipFile); + return zipFile; + } + + /** + * Call {@link #rethrow(Throwable)} with the given exception, but before throwing the exception, + * also close this Closer. Exceptions from closing are added to {@code t} as suppressed + * exceptions. + * + * @param t the throwable that should be re-thrown + * @throws IOException if {@code t} is an IOException, or one occurs + */ + public RuntimeException rethrowAndClose(Throwable t) throws IOException { + // bit of a hack here + try { + throw rethrow(t); + } finally { + try { + close(); + } catch (Throwable closeThrown) { + t.addSuppressed(closeThrown); + } + } + } + + /** + * Stores the given throwable and rethrows it. It will be rethrown as is if it is an + * {@code IOException}, {@code RuntimeException} or {@code Error}. Otherwise, it will be rethrown + * wrapped in a {@code RuntimeException}. Note: Be sure to declare all of the checked + * exception types your try block can throw when calling an overload of this method so as to avoid + * losing the original exception type. + * + *

This method always throws, and as such should be called as + * {@code throw closer.rethrow(e);} to ensure the compiler knows that it will throw. + * + * @return this method does not return; it always throws + * @throws IOException when the given throwable is an IOException + */ + public RuntimeException rethrow(Throwable e) throws IOException { + thrown = e; + Throwables.propagateIfPossible(e, IOException.class); + Throwables.throwIfUnchecked(e); + throw new RuntimeException(e); + } + + /** + * Stores the given throwable and rethrows it. It will be rethrown as is if it is an + * {@code IOException}, {@code RuntimeException}, {@code Error} or a checked exception of the + * given type. Otherwise, it will be rethrown wrapped in a {@code RuntimeException}. Note: + * Be sure to declare all of the checked exception types your try block can throw when calling an + * overload of this method so as to avoid losing the original exception type. + * + *

This method always throws, and as such should be called as + * {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it will throw. + * + * @return this method does not return; it always throws + * @throws IOException when the given throwable is an IOException + * @throws X when the given throwable is of the declared type X + */ + public RuntimeException rethrow(Throwable e, + Class declaredType) throws IOException, X { + thrown = e; + Throwables.propagateIfPossible(e, IOException.class); + Throwables.propagateIfPossible(e, declaredType); + Throwables.throwIfUnchecked(e); + throw new RuntimeException(e); + } + + /** + * Stores the given throwable and rethrows it. It will be rethrown as is if it is an + * {@code IOException}, {@code RuntimeException}, {@code Error} or a checked exception of either + * of the given types. Otherwise, it will be rethrown wrapped in a {@code RuntimeException}. + * Note: Be sure to declare all of the checked exception types your try block can throw + * when calling an overload of this method so as to avoid losing the original exception type. + * + *

This method always throws, and as such should be called as + * {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it will throw. + * + * @return this method does not return; it always throws + * @throws IOException when the given throwable is an IOException + * @throws X1 when the given throwable is of the declared type X1 + * @throws X2 when the given throwable is of the declared type X2 + */ + public RuntimeException rethrow( + Throwable e, Class declaredType1, Class declaredType2) throws IOException, X1, X2 { + thrown = e; + Throwables.propagateIfPossible(e, IOException.class); + Throwables.propagateIfPossible(e, declaredType1, declaredType2); + Throwables.throwIfUnchecked(e); + throw new RuntimeException(e); + } + + /** + * Closes all {@code Closeable} instances that have been added to this {@code Closer}. If an + * exception was thrown in the try block and passed to one of the {@code exceptionThrown} methods, + * any exceptions thrown when attempting to close a closeable will be suppressed. Otherwise, the + * first exception to be thrown from an attempt to close a closeable will be thrown and any + * additional exceptions that are thrown after that will be suppressed. + */ + @Override + public void close() throws IOException { + Throwable throwable = thrown; + + // close closeables in LIFO order + while (!stack.isEmpty()) { + Closeable closeable = stack.pop(); + try { + closeable.close(); + } catch (Throwable e) { + if (throwable == null) { + throwable = e; + } else { + suppressor.suppress(closeable, throwable, e); + } + } + } + while (!zipStack.isEmpty()) { + ZipFile zipFile = zipStack.pop(); + try { + zipFile.close(); + } catch (Throwable e) { + if (throwable == null) { + throwable = e; + } else { + suppressor.suppress(zipFile, throwable, e); + } + } + } + + if (thrown == null && throwable != null) { + Throwables.propagateIfPossible(throwable, IOException.class); + throw new AssertionError(throwable); // not possible + } + } + + /** + * Suppression strategy interface. + */ + @VisibleForTesting interface Suppressor { + /** + * Suppresses the given exception ({@code suppressed}) which was thrown when attempting to close + * the given closeable. {@code thrown} is the exception that is actually being thrown from the + * method. Implementations of this method should not throw under any circumstances. + */ + void suppress(Object closeable, Throwable thrown, Throwable suppressed); + } + + /** + * Suppresses exceptions by logging them. + */ + @VisibleForTesting static final class LoggingSuppressor implements Suppressor { + + static final LoggingSuppressor INSTANCE = new LoggingSuppressor(); + + @Override + public void suppress(Object closeable, Throwable thrown, Throwable suppressed) { + // log to the same place as Closeables + LOGGER.warn("Suppressing exception thrown when closing " + closeable, suppressed); + } + } + + /** + * Suppresses exceptions by adding them to the exception that will be thrown using JDK7's + * addSuppressed(Throwable) mechanism. + */ + @VisibleForTesting static final class SuppressingSuppressor implements Suppressor { + + static final SuppressingSuppressor INSTANCE = new SuppressingSuppressor(); + + static boolean isAvailable() { + return addSuppressed != null; + } + + static final Method addSuppressed = getAddSuppressed(); + + private static Method getAddSuppressed() { + try { + return Throwable.class.getMethod("addSuppressed", Throwable.class); + } catch (Throwable e) { + return null; + } + } + + @Override + public void suppress(Object closeable, Throwable thrown, Throwable suppressed) { + // ensure no exceptions from addSuppressed + if (thrown == suppressed) { + return; + } + try { + addSuppressed.invoke(thrown, suppressed); + } catch (Throwable e) { + // if, somehow, IllegalAccessException or another exception is thrown, fall back to logging + LoggingSuppressor.INSTANCE.suppress(closeable, thrown, suppressed); + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java b/src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java new file mode 100644 index 0000000..3fb87bd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java @@ -0,0 +1,102 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io; + +import java.io.IOException; +import java.io.InputStream; + +public class ForwardSeekableInputStream extends InputStream { + + protected InputStream parent; + protected long position = 0; + + public ForwardSeekableInputStream(InputStream parent) { + this.parent = parent; + } + + @Override + public int read() throws IOException { + int ret = parent.read(); + ++position; + return ret; + } + + @Override + public int available() throws IOException { + return parent.available(); + } + + @Override + public void close() throws IOException { + parent.close(); + } + + @Override + public synchronized void mark(int readlimit) { + parent.mark(readlimit); + } + + @Override + public boolean markSupported() { + return parent.markSupported(); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int read = super.read(b, off, len); + position += read; + return read; + } + + @Override + public int read(byte[] b) throws IOException { + int read = parent.read(b); + position += read; + return read; + } + + @Override + public synchronized void reset() throws IOException { + parent.reset(); + } + + @Override + public long skip(long n) throws IOException { + long skipped = parent.skip(n); + position += skipped; + return skipped; + } + + public void seek(long n) throws IOException { + long diff = n - position; + + if (diff < 0) { + throw new IOException("Can't seek backwards"); + } + + if (diff == 0) { + return; + } + + if (skip(diff) < diff) { + throw new IOException("Failed to seek " + diff + " bytes"); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java b/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java new file mode 100644 index 0000000..4e7a31f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Path; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * An abstract loader that handles loading resources from bundled URLs or local + * files. + */ +public interface ResourceLoader { + + /** + * Gets the bundled resource URL by name, relative to the provided class. + * + *

+ * The path name must not start with {@code /}. + *

+ * + * @param clazz The class to search relative to + * @param pathName The path name + * @return The URL to this bundled resource + * @throws IOException if an IO issue occurs + */ + @Nullable + default URL getResource(Class clazz, String pathName) throws IOException { + checkArgument(!pathName.startsWith("/"), "pathName must not start with /"); + String qualifiedName = clazz.getName().substring(0, clazz.getName().lastIndexOf('.')) + .replace(".", "/") + "/" + pathName; + return getRootResource(qualifiedName); + } + + /** + * Gets the bundled resource URL by name. + * + *

+ * The path name must not start with {@code /}. It is always + * absolute. + *

+ * + * @param pathName The path name + * @return The URL to this bundled resource + * @throws IOException if an IO issue occurs + */ + @Nullable + default URL getRootResource(String pathName) throws IOException { + checkArgument(!pathName.startsWith("/"), "pathName must not start with /"); + return this.getClass().getClassLoader().getResource(pathName); + } + + /** + * Gets the {@link Path} reference to this local resource. The file may not + * exist. + * + * @param pathName The path name + * @return The path reference + */ + Path getLocalResource(String pathName); +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/WorldEditResourceLoader.java b/src/main/java/com/sk89q/worldedit/util/io/WorldEditResourceLoader.java new file mode 100644 index 0000000..65a569d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/WorldEditResourceLoader.java @@ -0,0 +1,38 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io; + +import com.sk89q.worldedit.WorldEdit; + +import java.nio.file.Path; + +public class WorldEditResourceLoader implements ResourceLoader { + + private final WorldEdit worldEdit; + + public WorldEditResourceLoader(WorldEdit worldEdit) { + this.worldEdit = worldEdit; + } + + @Override + public Path getLocalResource(String pathName) { + return this.worldEdit.getWorkingDirectoryPath(pathName); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveDir.java b/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveDir.java new file mode 100644 index 0000000..29d02ad --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveDir.java @@ -0,0 +1,33 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import java.io.Closeable; +import java.nio.file.Path; + +/** + * Represents an archive opened as a directory. This must be closed after work on the Path is + * done. + */ +public interface ArchiveDir extends Closeable { + + Path getPath(); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveNioSupport.java b/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveNioSupport.java new file mode 100644 index 0000000..d237c3e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveNioSupport.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +/** + * Something that can provide access to an archive file as a file system. + */ +public interface ArchiveNioSupport { + + /** + * Try to open the given archive as a file system. + * + * @param archive the archive to open + * @return the path for the root of the archive, if available + */ + Optional tryOpenAsDir(Path archive) throws IOException; + +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveNioSupports.java b/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveNioSupports.java new file mode 100644 index 0000000..512f887 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveNioSupports.java @@ -0,0 +1,94 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import com.google.common.collect.ImmutableList; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.stream.Stream; + +public class ArchiveNioSupports { + + private static final List SUPPORTS; + + static { + ImmutableList.Builder builder = ImmutableList.builder(); + SUPPORTS = builder.add(ZipArchiveNioSupport.getInstance()) + .addAll(ServiceLoader.load(ArchiveNioSupport.class)) + .build(); + } + + public static Optional tryOpenAsDir(Path archive) throws IOException { + for (ArchiveNioSupport support : SUPPORTS) { + Optional fs = support.tryOpenAsDir(archive); + if (fs.isPresent()) { + return fs; + } + } + return Optional.empty(); + } + + private static final ArchiveNioSupport COMBINED = ArchiveNioSupports::tryOpenAsDir; + + /** + * Get an {@link ArchiveNioSupport} that combines all known instances. + * @return a combined {@link ArchiveNioSupport} instance + */ + public static ArchiveNioSupport combined() { + return COMBINED; + } + + /** + * If root contains a folder with the same name as {@code name}, and no regular files, + * returns the path to that folder. Otherwise, return the root path. + * + *

+ * This method is used to provide equal outputs for archives that do and do not contain + * their name as part of their root folder. + *

+ * + * @param root the root path + * @param name the name that might exist inside root + * @return the corrected path + */ + public static Path skipRootSameName(Path root, String name) throws IOException { + Path innerDir = root.resolve(name); + if (Files.isDirectory(innerDir)) { + try (Stream files = Files.list(root)) { + // The reason we check this, is that macOS creates a __MACOSX directory inside + // its zip files. We want to allow this to pass if that exists, or a similar + // mechanism, but fail if there are regular files, since that indicates that + // it may not be the right thing to do. + if (files.allMatch(Files::isDirectory)) { + return innerDir; + } + } + } + return root; + } + + private ArchiveNioSupports() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveUnpacker.java b/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveUnpacker.java new file mode 100644 index 0000000..16f37eb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/ArchiveUnpacker.java @@ -0,0 +1,122 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import com.google.common.collect.ImmutableSet; +import com.google.common.hash.Hasher; +import com.google.common.hash.Hashing; +import com.google.common.io.ByteProcessor; +import com.google.common.io.ByteStreams; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public final class ArchiveUnpacker { + + private static final String UNPACK_FINISHED = ".unpack_finished"; + + private static final Lock lock = new ReentrantLock(); + + private final Path unpackDir; + + public ArchiveUnpacker(Path unpackDir) throws IOException { + this.unpackDir = unpackDir; + Files.createDirectories(unpackDir); + } + + public Path unpackArchive(URL archiveUrl) throws IOException { + String hash; + try (InputStream data = archiveUrl.openStream()) { + hash = ByteStreams.readBytes(data, new ByteProcessor() { + private final Hasher hasher = Hashing.crc32c().newHasher(); + + @Override + public boolean processBytes(byte[] buf, int off, int len) { + hasher.putBytes(buf, off, len); + return true; + } + + @Override + public String getResult() { + return hasher.hash().toString(); + } + }); + } + Path dest = unpackDir.resolve(hash); + if (Files.exists(dest.resolve(UNPACK_FINISHED))) { + // trust this, no other option :) + return dest; + } + lock.lock(); + try { + // check again after exclusive acquire + if (Files.exists(dest.resolve(UNPACK_FINISHED))) { + return dest; + } + try (InputStream in = archiveUrl.openStream(); + ZipInputStream zipReader = new ZipInputStream(in)) { + ZipEntry next; + while ((next = zipReader.getNextEntry()) != null) { + Path resolved = dest.resolve(next.getName()); + if (!resolved.startsWith(dest)) { + // bad entry + continue; + } + if (next.isDirectory()) { + Files.createDirectories( + resolved, + SafeFiles.getOwnerOnlyFileAttributes(AttributeTarget.DIRECTORY) + ); + } else { + try (SeekableByteChannel channel = Files.newByteChannel( + resolved, + ImmutableSet.of( + StandardOpenOption.CREATE, + StandardOpenOption.WRITE, + StandardOpenOption.TRUNCATE_EXISTING + ), + SafeFiles.getOwnerOnlyFileAttributes(AttributeTarget.FILE) + )) { + ByteStreams.copy( + Channels.newChannel(zipReader), + channel + ); + } + } + } + } + Files.createFile(dest.resolve(UNPACK_FINISHED)); + return dest; + } finally { + lock.unlock(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/AttributeTarget.java b/src/main/java/com/sk89q/worldedit/util/io/file/AttributeTarget.java new file mode 100644 index 0000000..6f12c94 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/AttributeTarget.java @@ -0,0 +1,24 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +public enum AttributeTarget { + FILE, DIRECTORY +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/FileSelectionAbortedException.java b/src/main/java/com/sk89q/worldedit/util/io/file/FileSelectionAbortedException.java new file mode 100644 index 0000000..14c2b77 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/FileSelectionAbortedException.java @@ -0,0 +1,38 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import net.kyori.text.Component; + +public class FileSelectionAbortedException extends FilenameException { + + public FileSelectionAbortedException() { + super(""); + } + + @Deprecated + public FileSelectionAbortedException(String msg) { + super("", msg); + } + + public FileSelectionAbortedException(Component msg) { + super("", msg); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/FilenameException.java b/src/main/java/com/sk89q/worldedit/util/io/file/FilenameException.java new file mode 100644 index 0000000..2cb9966 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/FilenameException.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.Component; + +public class FilenameException extends WorldEditException { + + private final String filename; + + public FilenameException(String filename) { + super(); + this.filename = filename; + } + + public FilenameException(String filename, Component msg) { + super(msg); + this.filename = filename; + } + + @Deprecated + public FilenameException(String filename, String msg) { + super(msg); + this.filename = filename; + } + + public String getFilename() { + return filename; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/FilenameResolutionException.java b/src/main/java/com/sk89q/worldedit/util/io/file/FilenameResolutionException.java new file mode 100644 index 0000000..86194f9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/FilenameResolutionException.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import net.kyori.text.Component; + +public class FilenameResolutionException extends FilenameException { + + public FilenameResolutionException(String filename) { + super(filename); + } + + public FilenameResolutionException(String filename, Component msg) { + super(filename, msg); + } + + @Deprecated + public FilenameResolutionException(String filename, String msg) { + super(filename, msg); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/InvalidFilenameException.java b/src/main/java/com/sk89q/worldedit/util/io/file/InvalidFilenameException.java new file mode 100644 index 0000000..13cb2b8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/InvalidFilenameException.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import net.kyori.text.Component; + +public class InvalidFilenameException extends FilenameException { + + public InvalidFilenameException(String filename) { + super(filename); + } + + public InvalidFilenameException(String filename, Component msg) { + super(filename, msg); + } + + @Deprecated + public InvalidFilenameException(String filename, String msg) { + super(filename, msg); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/MorePaths.java b/src/main/java/com/sk89q/worldedit/util/io/file/MorePaths.java new file mode 100644 index 0000000..4f12406 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/MorePaths.java @@ -0,0 +1,83 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Streams; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileTime; +import java.time.Instant; +import java.util.*; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public class MorePaths { + + public static Comparator oldestFirst() { + return Comparator.comparing(x -> { + try { + return Files.getLastModifiedTime(x); + } catch (IOException e) { + return FileTime.from(Instant.EPOCH); + } + }); + } + + public static Comparator newestFirst() { + return oldestFirst().reversed(); + } + + /** + * Starting with the first path element, add elements until reaching this path. + */ + public static Stream iterPaths(Path path) { + Deque parents = new ArrayDeque<>(path.getNameCount()); + // Push parents to the front of the stack, so the "root" is at the front + Path next = path; + while (next != null) { + parents.addFirst(next); + next = next.getParent(); + } + // now just iterate straight over them + return ImmutableList.copyOf(parents).stream(); + } + + /** + * Create an efficiently-splittable spliterator for the given path elements. + * + *

+ * Since paths are so small, this is only useful for preventing heavy computations + * on later parts of the stream from occurring when using + * {@link Streams#findLast(IntStream)}, and not for parallelism. + *

+ * + * @param path the path to create a spliterator for + * @return the spliterator + */ + public static Spliterator optimizedSpliterator(Path path) { + return Arrays.spliterator(Streams.stream(path).toArray(Path[]::new)); + } + + private MorePaths() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/SafeFiles.java b/src/main/java/com/sk89q/worldedit/util/io/file/SafeFiles.java new file mode 100644 index 0000000..f712702 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/SafeFiles.java @@ -0,0 +1,199 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import com.google.common.collect.ImmutableSet; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class SafeFiles { + + /** + * A version of {@link Files#list(Path)} that won't leak resources. + * + *

+ * Instead, it immediately consumes the entire listing into a {@link List} and + * calls {@link List#stream()}. + *

+ * + * @param dir the directory to list + * @return an I/O-resource-free stream of the files in the directory + * @throws IOException if an I/O error occurs + */ + public static Stream noLeakFileList(Path dir) throws IOException { + try (Stream stream = Files.list(dir)) { + return stream.collect(Collectors.toList()).stream(); + } + } + + /** + * {@link Path#getFileName()} includes a slash sometimes for some reason. + * This will get rid of it. + * + * @param path the path to get the file name for + * @return the file name of the given path + */ + public static String canonicalFileName(Path path) { + return dropSlash(path.getFileName().toString()); + } + + private static String dropSlash(String name) { + if (name.isEmpty() || name.codePointBefore(name.length()) != '/') { + return name; + } + return name.substring(0, name.length() - 1); + } + + /** + * Recursively uses {@link #tryHardToDelete(Path)} to cleanup directories before deleting them. + * + * @param directory the directory to delete + * @throws IOException if an error occurs trying to delete the directory + */ + public static void tryHardToDeleteDir(Path directory) throws IOException { + if (!Files.isDirectory(directory)) { + if (!Files.exists(directory)) { + return; + } + + throw new IOException(directory + " is not a directory"); + } + try (Stream files = Files.list(directory)) { + for (Iterator iter = files.iterator(); iter.hasNext(); ) { + Path next = iter.next(); + if (Files.isDirectory(next)) { + tryHardToDeleteDir(next); + } else { + tryHardToDelete(next); + } + } + } + tryHardToDelete(directory); + } + + /** + * Tries to delete a path. If it fails the first time, uses an implementation detail to try + * and make it possible to delete the path, and then tries again. If that fails, throws an + * {@link IOException} with both errors. + * + * @param path the path to delete + * @throws IOException if the path could not be deleted after multiple attempts + */ + public static void tryHardToDelete(Path path) throws IOException { + IOException suppressed = tryDelete(path); + if (suppressed == null) { + return; + } + + // This is copied from Ant (see org.apache.tools.ant.util.FileUtils.tryHardToDelete). + // It mentions that there is a bug in the Windows JDK implementations that this is a valid + // workaround for. I've been unable to find a definitive reference to this bug. + // The thinking is that if this is good enough for Ant, it's good enough for us. + System.gc(); + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + + IOException suppressed2 = tryDelete(path); + if (suppressed2 == null) { + return; + } + IOException ex = new IOException("Failed to delete " + path, suppressed2); + ex.addSuppressed(suppressed); + throw ex; + } + + @Nullable + private static IOException tryDelete(Path path) { + try { + Files.deleteIfExists(path); + if (Files.exists(path)) { + return new IOException(path + " still exists after deleting"); + } + return null; + } catch (IOException e) { + return e; + } + } + + private static final FileAttribute[] OWNER_ONLY_FILE_ATTRS; + private static final FileAttribute[] OWNER_ONLY_DIR_ATTRS; + + static { + if (FileSystems.getDefault().supportedFileAttributeViews().contains("posix")) { + OWNER_ONLY_FILE_ATTRS = new FileAttribute[] { + PosixFilePermissions.asFileAttribute( + ImmutableSet.of( + PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_WRITE + ) + ) + }; + OWNER_ONLY_DIR_ATTRS = new FileAttribute[] { + PosixFilePermissions.asFileAttribute( + ImmutableSet.of( + PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_WRITE, + PosixFilePermission.OWNER_EXECUTE + ) + ) + }; + } else { + OWNER_ONLY_FILE_ATTRS = new FileAttribute[0]; + OWNER_ONLY_DIR_ATTRS = new FileAttribute[0]; + } + } + + /** + * Get a set of file attributes for file creation with owner-only access, if possible. + * + *

+ * On POSIX, this returns o+rw (and o+x if directory), on Windows it returns nothing. + *

+ * + * @return the owner-only file attributes + */ + public static FileAttribute[] getOwnerOnlyFileAttributes(AttributeTarget attributeTarget) { + switch (attributeTarget) { + case FILE: + return OWNER_ONLY_FILE_ATTRS; + case DIRECTORY: + return OWNER_ONLY_DIR_ATTRS; + default: + throw new IllegalStateException("Unknown attribute target " + attributeTarget); + } + } + + private SafeFiles() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/io/file/ZipArchiveNioSupport.java b/src/main/java/com/sk89q/worldedit/util/io/file/ZipArchiveNioSupport.java new file mode 100644 index 0000000..0a60d3d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/io/file/ZipArchiveNioSupport.java @@ -0,0 +1,64 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.io.file; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.Optional; + +public final class ZipArchiveNioSupport implements ArchiveNioSupport { + + private static final ZipArchiveNioSupport INSTANCE = new ZipArchiveNioSupport(); + + public static ZipArchiveNioSupport getInstance() { + return INSTANCE; + } + + private ZipArchiveNioSupport() { + } + + @Override + public Optional tryOpenAsDir(Path archive) throws IOException { + if (!archive.getFileName().toString().endsWith(".zip")) { + return Optional.empty(); + } + FileSystem zipFs = FileSystems.newFileSystem( + archive, getClass().getClassLoader() + ); + Path root = ArchiveNioSupports.skipRootSameName( + zipFs.getPath("/"), archive.getFileName().toString() + .replaceFirst("\\.zip$", "") + ); + return Optional.of(new ArchiveDir() { + @Override + public Path getPath() { + return root; + } + + @Override + public void close() throws IOException { + zipFs.close(); + } + }); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/lifecycle/ConstantLifecycled.java b/src/main/java/com/sk89q/worldedit/util/lifecycle/ConstantLifecycled.java new file mode 100644 index 0000000..41cb210 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/lifecycle/ConstantLifecycled.java @@ -0,0 +1,55 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.lifecycle; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiConsumer; + +/** + * A {@link Lifecycled} that never invalidates. + */ +public final class ConstantLifecycled implements Lifecycled { + private final T value; + + public ConstantLifecycled(T value) { + this.value = Objects.requireNonNull(value); + } + + @Override + public Optional value() { + return Optional.of(value); + } + + @Override + public Events events() { + // Simple implementation, we just need to call onNewValue + return new Events() { + @Override + public void onNewValue(O owner, BiConsumer> callback) { + callback.accept(owner, ConstantLifecycled.this); + } + + @Override + public void onInvalidated(O owner, BiConsumer> callback) { + } + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/lifecycle/FlatMapLifecycled.java b/src/main/java/com/sk89q/worldedit/util/lifecycle/FlatMapLifecycled.java new file mode 100644 index 0000000..e2cf7bb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/lifecycle/FlatMapLifecycled.java @@ -0,0 +1,80 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.lifecycle; + +import javax.annotation.Nullable; +import java.util.Optional; +import java.util.function.Function; + +class FlatMapLifecycled implements Lifecycled { + private final LifecycledCallbackHandler events = new LifecycledCallbackHandler<>(this); + private Lifecycled mapped; + private Token> mappedToken; + @Nullable + private U value; + + FlatMapLifecycled(Lifecycled upstream, Function> mapper) { + upstream.events().onInvalidated(this, (this$, up) -> { + boolean fire = this$.value != null; + this$.value = null; + // drop `mapped` hooks if needed + this$.mappedToken = null; + this$.mapped = null; + if (fire) { + this$.events.fireInvalidated(); + } + }); + upstream.events().onNewValue(this, (this$, up) -> { + this$.mapped = mapper.apply(up.valueOrThrow()); + this$.mappedToken = new Token<>(this$); + mapped.events().onInvalidated(this$.mappedToken, (token, mapped$) -> { + boolean fire = token.inner.value != null; + token.inner.value = null; + // note we do not drop the token here, onNewValue may be called again + if (fire) { + this$.events.fireInvalidated(); + } + }); + mapped.events().onNewValue(this$.mappedToken, (token, mapped$) -> { + U newValue = mapped$.valueOrThrow(); + boolean fire = token.inner.value != newValue; + token.inner.value = newValue; + if (fire) { + this$.events.fireOnNewValue(); + } + }); + }); + } + + @Override + public Optional value() { + return Optional.ofNullable(value); + } + + @Override + public boolean isValid() { + return value != null; + } + + @Override + public Events events() { + return events; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/lifecycle/Lifecycled.java b/src/main/java/com/sk89q/worldedit/util/lifecycle/Lifecycled.java new file mode 100644 index 0000000..d9d2c7f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/lifecycle/Lifecycled.java @@ -0,0 +1,151 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.lifecycle; + +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Represents an object with a simple valid/invalid lifecycle. + * + *

+ * A lifecycled object will start with no value, then trigger + * {@link Events#onNewValue(Object, BiConsumer)} callbacks when it gets one, and + * {@link Events#onInvalidated(Object, BiConsumer)} callbacks when it loses it. A full + * invalidated->new value cycle is called a "reload". + *

+ * + *

+ * Downstream lifecycled objects can be derived using functional methods, and share some + * common rules. They will apply the operation sometime before the result is needed, either + * eagerly or lazily. They will re-do the operation after the upstream {@link Lifecycled} is + * reloaded. + *

+ * + *

+ * Unless specified, {@link Lifecycled} objects are not thread-safe. However, the + * {@link Events} objects are, and callbacks may be added from any thread. + *

+ * + * @param the value type + */ +public interface Lifecycled { + + interface Events { + /** + * Add a callback for when this lifecycled is given a new value. Will be called immediately + * if this lifecycled is currently valid. + * + *

+ * The callback should not reference the owner, it must only access it via the parameter. + * This ensures that the owner will be GC-able, otherwise it may be stuck in a reference + * loop. + *

+ * + * @param owner when the owner is GC'd, the callback is removed + * @param callback the callback, will be passed the lifecycled object + */ + void onNewValue(O owner, BiConsumer> callback); + + /** + * Add a callback for when this lifecycled is invalidated. Will be called immediately if + * this lifecycled is currently invalid. + * + *

+ * The callback should not reference the owner, it must only access it via the parameter. + * This ensures that the owner will be GC-able, otherwise it may be stuck in a reference + * loop. + *

+ * + * @param owner when the owner is GC'd, the callback is removed + * @param callback the callback, will be passed the lifecycled object + */ + void onInvalidated(O owner, BiConsumer> callback); + } + + /** + * Get the value or {@link Optional#empty()}. + * + * @return the value + */ + Optional value(); + + /** + * Get the value or throw. + * + * @return the value + * @throws IllegalStateException if there is no value + */ + default T valueOrThrow() throws IllegalStateException { + return value().orElseThrow(() -> new IllegalStateException("Currently invalid")); + } + + /** + * Check for validity, usually without triggering computation. + * + * @return if this lifecycled's {@link #value()} is valid + */ + default boolean isValid() { + return value().isPresent(); + } + + /** + * Get the event manager for this lifecycled object. + * + * @return the event manager + */ + Events events(); + + /** + * Map the value. + * + * @param mapper the mapper function + * @param the new type + * @return the downstream lifecycled + */ + default Lifecycled map(Function mapper) { + return new MapLifecycled<>(this, mapper); + } + + /** + * Filter the value. In other words, create a new lifecycled object where validity is ANDed + * with the result of calling the filter function. + * + * @param filterer the filter function + * @return the downstream lifecycled + */ + default Lifecycled filter(Predicate filterer) { + SimpleLifecycled downstream = SimpleLifecycled.invalid(); + events().onInvalidated(downstream, (d, lifecycled) -> d.invalidate()); + events().onNewValue(downstream, (d, lifecycled) -> { + T value = lifecycled.valueOrThrow(); + if (filterer.test(value)) { + d.newValue(value); + } + }); + return downstream; + } + + default Lifecycled flatMap(Function> mapper) { + return new FlatMapLifecycled<>(this, mapper); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/lifecycle/LifecycledCallbackHandler.java b/src/main/java/com/sk89q/worldedit/util/lifecycle/LifecycledCallbackHandler.java new file mode 100644 index 0000000..4493764 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/lifecycle/LifecycledCallbackHandler.java @@ -0,0 +1,114 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.lifecycle; + +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiConsumer; + +/** + * Convenience class for implementing the callbacks of {@link Lifecycled}. + */ +public class LifecycledCallbackHandler implements Lifecycled.Events { + private final Lifecycled lifecycled; + private final Lock lock = new ReentrantLock(); + private final Map>> onInvalidatedCallbacks = + new WeakHashMap<>(); + private final Map>> onNewValueCallbacks = + new WeakHashMap<>(); + + public LifecycledCallbackHandler(Lifecycled lifecycled) { + this.lifecycled = lifecycled; + } + + @Override + public void onInvalidated(O owner, BiConsumer> callback) { + lock.lock(); + try { + onInvalidatedCallbacks.put(owner, callback); + if (!lifecycled.isValid()) { + callback.accept(owner, lifecycled); + } + } finally { + lock.unlock(); + } + } + + @Override + public void onNewValue(O owner, BiConsumer> callback) { + lock.lock(); + try { + onNewValueCallbacks.put(owner, callback); + if (lifecycled.isValid()) { + callback.accept(owner, lifecycled); + } + } finally { + lock.unlock(); + } + } + + + /** + * Fire {@link #onInvalidated(Object, BiConsumer)} callbacks. + */ + public void fireInvalidated() { + lock.lock(); + try { + for (Map.Entry>> callback : onInvalidatedCallbacks.entrySet()) { + Object owner = callback.getKey(); + if (owner == null) { + // GC'd, continue + continue; + } + @SuppressWarnings("unchecked") + BiConsumer> cast = + (BiConsumer>) callback.getValue(); + cast.accept(owner, lifecycled); + } + } finally { + lock.unlock(); + } + } + + /** + * Fire {@link #onNewValue(Object, BiConsumer)} callbacks, the {@link Lifecycled#value()} must + * be available. + */ + public void fireOnNewValue() { + lock.lock(); + try { + for (Map.Entry>> callback : onNewValueCallbacks.entrySet()) { + Object owner = callback.getKey(); + if (owner == null) { + // GC'd, continue + continue; + } + @SuppressWarnings("unchecked") + BiConsumer> cast = + (BiConsumer>) callback.getValue(); + cast.accept(owner, lifecycled); + } + } finally { + lock.unlock(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/lifecycle/MapLifecycled.java b/src/main/java/com/sk89q/worldedit/util/lifecycle/MapLifecycled.java new file mode 100644 index 0000000..9958c95 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/lifecycle/MapLifecycled.java @@ -0,0 +1,82 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.lifecycle; + +import javax.annotation.Nullable; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +class MapLifecycled implements Lifecycled { + private final LifecycledCallbackHandler events = new LifecycledCallbackHandler<>(this); + private final Lifecycled upstream; + private final Function mapper; + @Nullable + private U cache; + private boolean computable; + + MapLifecycled(Lifecycled upstream, Function mapper) { + this.upstream = upstream; + this.mapper = mapper; + upstream.events().onInvalidated(this, (this$, __) -> { + boolean fire = this$.computable; + this$.cache = null; + this$.computable = false; + if (fire) { + this$.events.fireInvalidated(); + } + }); + upstream.events().onNewValue(this, (this$, __) -> { + boolean fire = !this$.computable; + this$.computable = true; + if (fire) { + this$.events.fireOnNewValue(); + } + }); + } + + private void compute() { + T value = upstream.value().orElseThrow(() -> + new AssertionError("Upstream lost value without calling onInvalidated event") + ); + this.cache = Objects.requireNonNull(mapper.apply(value), "Mapper cannot produce null"); + } + + @Override + public Optional value() { + if (!computable) { + return Optional.empty(); + } + if (cache == null) { + compute(); + } + return Optional.of(cache); + } + + @Override + public boolean isValid() { + return computable; + } + + @Override + public Events events() { + return events; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/lifecycle/SimpleLifecycled.java b/src/main/java/com/sk89q/worldedit/util/lifecycle/SimpleLifecycled.java new file mode 100644 index 0000000..2c97d48 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/lifecycle/SimpleLifecycled.java @@ -0,0 +1,79 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.lifecycle; + +import java.util.Objects; +import java.util.Optional; +import javax.annotation.Nullable; + +/** + * A {@link Lifecycled} that can be directly called to {@linkplain #invalidate() invalidate} it or + * set a {@linkplain #newValue(Object) new value}. + */ +public final class SimpleLifecycled implements Lifecycled { + public static SimpleLifecycled valid(T value) { + return new SimpleLifecycled<>(Objects.requireNonNull(value)); + } + + public static SimpleLifecycled invalid() { + return new SimpleLifecycled<>(null); + } + + private final LifecycledCallbackHandler events = new LifecycledCallbackHandler<>(this); + @Nullable + private T value; + + private SimpleLifecycled(@Nullable T value) { + this.value = value; + } + + /** + * Set the value of this lifecycled and fire the new value event. + * + * @param value the value + */ + public void newValue(T value) { + // Ensure lifecycle constraints are upheld. + invalidate(); + this.value = Objects.requireNonNull(value); + events.fireOnNewValue(); + } + + /** + * Remove the value of this lifecycled and fire the invalidated event. + */ + public void invalidate() { + boolean fire = this.value != null; + this.value = null; + if (fire) { + events.fireInvalidated(); + } + } + + @Override + public Optional value() { + return Optional.ofNullable(value); + } + + @Override + public Events events() { + return events; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/lifecycle/Token.java b/src/main/java/com/sk89q/worldedit/util/lifecycle/Token.java new file mode 100644 index 0000000..b721ec8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/lifecycle/Token.java @@ -0,0 +1,33 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.lifecycle; + +/** + * Used to create a new strong reference to an object that can be separately dropped. + * + * @param the inner object + */ +class Token { + final T inner; + + Token(T inner) { + this.inner = inner; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/logging/DynamicStreamHandler.java b/src/main/java/com/sk89q/worldedit/util/logging/DynamicStreamHandler.java new file mode 100644 index 0000000..adb6d0c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/logging/DynamicStreamHandler.java @@ -0,0 +1,179 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.logging; + +import javax.annotation.Nullable; +import java.io.UnsupportedEncodingException; +import java.util.logging.*; + +/** + * A {@link StreamHandler} delegate that allows for the swap and disable of + * another handler. When {@link #setHandler(StreamHandler)} is called with + * null, then records passed onto this handler will be dropped. Otherwise, + * the delegate handler will receive those records. + */ +public class DynamicStreamHandler extends StreamHandler { + + private @Nullable StreamHandler handler; + private @Nullable Formatter formatter; + private @Nullable Filter filter; + private @Nullable String encoding; + private Level level = Level.ALL; + + /** + * Get the delegate handler. + * + * @return the delegate handler (Which may be null) + */ + public @Nullable synchronized StreamHandler getHandler() { + return handler; + } + + /** + * Set the handler. + * + * @param handler the delegate handler (which can be null) + */ + public synchronized void setHandler(@Nullable StreamHandler handler) { + if (this.handler != null) { + this.handler.close(); + } + + this.handler = handler; + + if (handler != null) { + handler.setFormatter(formatter); + handler.setFilter(filter); + try { + handler.setEncoding(encoding); + } catch (UnsupportedEncodingException ignored) { + } + handler.setLevel(level); + } + } + + @Override + public synchronized void publish(LogRecord record) { + if (handler != null) { + handler.publish(record); + } + } + + @Override + public synchronized void close() throws SecurityException { + if (handler != null) { + handler.close(); + } + } + + @Override + public void setEncoding(@Nullable String encoding) throws SecurityException, UnsupportedEncodingException { + StreamHandler handler = this.handler; + this.encoding = encoding; + if (handler != null) { + handler.setEncoding(encoding); + } + } + + @Override + public boolean isLoggable(LogRecord record) { + StreamHandler handler = this.handler; + return handler != null && handler.isLoggable(record); + } + + @Override + public synchronized void flush() { + StreamHandler handler = this.handler; + if (handler != null) { + handler.flush(); + } + } + + @Override + public void setFormatter(@Nullable Formatter newFormatter) throws SecurityException { + StreamHandler handler = this.handler; + this.formatter = newFormatter; + if (handler != null) { + handler.setFormatter(newFormatter); + } + } + + @Override + public Formatter getFormatter() { + StreamHandler handler = this.handler; + Formatter formatter = this.formatter; + if (handler != null) { + return handler.getFormatter(); + } else if (formatter != null) { + return formatter; + } else { + return new SimpleFormatter(); + } + } + + @Override + public String getEncoding() { + StreamHandler handler = this.handler; + String encoding = this.encoding; + if (handler != null) { + return handler.getEncoding(); + } else { + return encoding; + } + } + + @Override + public void setFilter(@Nullable Filter newFilter) throws SecurityException { + StreamHandler handler = this.handler; + this.filter = newFilter; + if (handler != null) { + handler.setFilter(newFilter); + } + } + + @Override + public Filter getFilter() { + StreamHandler handler = this.handler; + Filter filter = this.filter; + if (handler != null) { + return handler.getFilter(); + } else { + return filter; + } + } + + @Override + public synchronized void setLevel(Level newLevel) throws SecurityException { + if (handler != null) { + handler.setLevel(newLevel); + } + this.level = newLevel; + } + + @Override + public synchronized Level getLevel() { + if (handler != null) { + return handler.getLevel(); + } else { + return level; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/logging/LogFormat.java b/src/main/java/com/sk89q/worldedit/util/logging/LogFormat.java new file mode 100644 index 0000000..a67de73 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/logging/LogFormat.java @@ -0,0 +1,83 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.logging; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Date; +import java.util.logging.Formatter; +import java.util.logging.LogRecord; + +/** + * A standard logging format for WorldEdit. + */ +public class LogFormat extends Formatter { + public static final String DEFAULT_FORMAT = "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s]: %5$s%6$s%n"; + private final Date dat = new Date(); + private final String format; + + public LogFormat() { + this(null); + } + + public LogFormat(String format) { + if (format == null || format.isEmpty()) { + format = DEFAULT_FORMAT; + } + try { + //noinspection ResultOfMethodCallIgnored + String.format(format, new Date(), "", "", "", "", ""); + } catch (IllegalArgumentException var3) { + format = DEFAULT_FORMAT; + } + this.format = format; + } + + @Override + public String format(LogRecord record) { + dat.setTime(record.getMillis()); + String source; + if (record.getSourceClassName() != null) { + source = record.getSourceClassName(); + if (record.getSourceMethodName() != null) { + source += " " + record.getSourceMethodName(); + } + } else { + source = record.getLoggerName(); + } + String message = formatMessage(record); + String throwable = ""; + if (record.getThrown() != null) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + pw.println(); + record.getThrown().printStackTrace(pw); + pw.close(); + throwable = sw.toString(); + } + return String.format(format, + dat, + source, + record.getLoggerName(), + record.getLevel().getName(), + message, + throwable); + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java b/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java new file mode 100644 index 0000000..a9a9243 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java @@ -0,0 +1,528 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.net; + +import com.google.common.base.Joiner; +import com.google.common.collect.Maps; +import com.google.common.net.UrlEscapers; +import com.sk89q.worldedit.util.io.Closer; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; + +public class HttpRequest implements Closeable { + + private static final int CONNECT_TIMEOUT = 1000 * 5; + private static final int READ_TIMEOUT = 1000 * 5; + private static final int READ_BUFFER_SIZE = 1024 * 8; + + private final Map headers = new HashMap<>(); + private final String method; + private final URL url; + private String contentType; + private byte[] body; + private HttpURLConnection conn; + private InputStream inputStream; + + private long contentLength = -1; + private long readBytes = 0; + + /** + * Create a new HTTP request. + * + * @param method the method + * @param url the URL + */ + private HttpRequest(String method, URL url) { + this.method = method; + this.url = url; + } + + /** + * Submit data. + * + * @return this object + */ + public HttpRequest body(String data) { + body = data.getBytes(); + return this; + } + + /** + * Submit form data. + * + * @param form the form + * @return this object + */ + public HttpRequest bodyUrlEncodedForm(Form form) { + contentType = "application/x-www-form-urlencoded"; + body = form.toUrlEncodedString().getBytes(StandardCharsets.UTF_8); + return this; + } + + /** + * Submit form data. + * + * @param form the form + * @return this object + */ + public HttpRequest bodyMultipartForm(Form form) { + contentType = "multipart/form-data;boundary=" + form.getFormDataSeparator(); + body = form.toFormDataString().getBytes(StandardCharsets.UTF_8); + return this; + } + + /** + * Add a header. + * + * @param key the header key + * @param value the header value + * @return this object + */ + public HttpRequest header(String key, String value) { + if (key.equalsIgnoreCase("Content-Type")) { + contentType = value; + } else { + headers.put(key, value); + } + return this; + } + + /** + * Execute the request. + *

+ * After execution, {@link #close()} should be called. + * + * @return this object + * @throws IOException on I/O error + */ + public HttpRequest execute() throws IOException { + boolean successful = false; + + try { + if (conn != null) { + throw new IllegalArgumentException("Connection already executed"); + } + + conn = (HttpURLConnection) reformat(url).openConnection(); + conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Java)"); + + if (body != null) { + conn.setRequestProperty("Content-Type", contentType); + conn.setRequestProperty("Content-Length", Integer.toString(body.length)); + conn.setDoInput(true); + } + + for (Map.Entry entry : headers.entrySet()) { + conn.setRequestProperty(entry.getKey(), entry.getValue()); + } + + conn.setRequestMethod(method); + conn.setUseCaches(false); + conn.setDoOutput(true); + conn.setConnectTimeout(CONNECT_TIMEOUT); + conn.setReadTimeout(READ_TIMEOUT); + + conn.connect(); + + if (body != null) { + DataOutputStream out = new DataOutputStream(conn.getOutputStream()); + out.write(body); + out.flush(); + out.close(); + } + + inputStream = conn.getResponseCode() == HttpURLConnection.HTTP_OK + ? conn.getInputStream() + : conn.getErrorStream(); + + successful = true; + } finally { + if (!successful) { + close(); + } + } + + return this; + } + + /** + * Require that the response code is one of the given response codes. + * + * @param codes a list of codes + * @return this object + * @throws IOException if there is an I/O error or the response code is not expected + */ + public HttpRequest expectResponseCode(int... codes) throws IOException { + int responseCode = getResponseCode(); + + for (int code : codes) { + if (code == responseCode) { + return this; + } + } + + close(); + throw new IOException("Did not get expected response code, got " + responseCode + " for " + url); + } + + /** + * Get the response code. + * + * @return the response code + * @throws IOException on I/O error + */ + public int getResponseCode() throws IOException { + if (conn == null) { + throw new IllegalArgumentException("No connection has been made"); + } + + return conn.getResponseCode(); + } + + /** + * Get the input stream. + * + * @return the input stream + */ + public InputStream getInputStream() { + return inputStream; + } + + /** + * Buffer the returned response. + * + * @return the buffered response + * @throws IOException on I/O error + * @throws InterruptedException on interruption + */ + public BufferedResponse returnContent() throws IOException, InterruptedException { + if (inputStream == null) { + throw new IllegalArgumentException("No input stream available"); + } + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + int b = 0; + while ((b = inputStream.read()) != -1) { + bos.write(b); + } + return new BufferedResponse(bos.toByteArray()); + } finally { + close(); + } + } + + /** + * Save the result to a file. + * + * @param file the file + * @return this object + * @throws IOException on I/O error + * @throws InterruptedException on interruption + */ + public HttpRequest saveContent(File file) throws IOException, InterruptedException { + Closer closer = Closer.create(); + + try { + FileOutputStream fos = closer.register(new FileOutputStream(file)); + BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos)); + + saveContent(bos); + } finally { + closer.close(); + } + + return this; + } + + /** + * Save the result to an output stream. + * + * @param out the output stream + * @return this object + * @throws IOException on I/O error + * @throws InterruptedException on interruption + */ + public HttpRequest saveContent(OutputStream out) throws IOException, InterruptedException { + BufferedInputStream bis; + + try { + String field = conn.getHeaderField("Content-Length"); + if (field != null) { + long len = Long.parseLong(field); + if (len >= 0) { // Let's just not deal with really big numbers + contentLength = len; + } + } + } catch (NumberFormatException ignored) { + } + + try { + bis = new BufferedInputStream(inputStream); + + byte[] data = new byte[READ_BUFFER_SIZE]; + int len = 0; + while ((len = bis.read(data, 0, READ_BUFFER_SIZE)) >= 0) { + out.write(data, 0, len); + readBytes += len; + } + } finally { + close(); + } + + return this; + } + + @Override + public void close() { + if (conn != null) { + conn.disconnect(); + } + } + + /** + * Perform a GET request. + * + * @param url the URL + * @return a new request object + */ + public static HttpRequest get(URL url) { + return request("GET", url); + } + + /** + * Perform a POST request. + * + * @param url the URL + * @return a new request object + */ + public static HttpRequest post(URL url) { + return request("POST", url); + } + + /** + * Perform a request. + * + * @param method the method + * @param url the URL + * @return a new request object + */ + public static HttpRequest request(String method, URL url) { + return new HttpRequest(method, url); + } + + /** + * Create a new {@link URL} and throw a {@link RuntimeException} if the URL + * is not valid. + * + * @param url the url + * @return a URL object + * @throws RuntimeException if the URL is invalid + */ + public static URL url(String url) { + try { + return new URL(url); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + /** + * URL may contain spaces and other nasties that will cause a failure. + * + * @param existing the existing URL to transform + * @return the new URL, or old one if there was a failure + */ + private static URL reformat(URL existing) { + try { + URL url = new URL(existing.toString()); + URI uri = new URI( + url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), + url.getPath(), url.getQuery(), url.getRef()); + url = uri.toURL(); + return url; + } catch (MalformedURLException | URISyntaxException e) { + return existing; + } + } + + /** + * Used with {@link #bodyUrlEncodedForm(Form)}. + */ + public static final class Form { + + private static final Joiner.MapJoiner URL_ENCODER = Joiner.on('&') + .withKeyValueSeparator('='); + private static final Joiner CRLF_JOINER = Joiner.on("\r\n"); + + public final Map elements = new LinkedHashMap<>(); + + private final String formDataSeparator = "EngineHubFormData" + + ThreadLocalRandom.current().nextInt(10000, 99999); + + private Form() { + } + + /** + * Add a key/value to the form. + * + * @param key the key + * @param value the value + * @return this object + */ + public Form add(String key, String value) { + elements.put(key, value); + return this; + } + + public String getFormDataSeparator() { + return formDataSeparator; + } + + public String toFormDataString() { + String separatorWithDashes = "--" + formDataSeparator; + StringBuilder builder = new StringBuilder(); + + for (Map.Entry element : elements.entrySet()) { + CRLF_JOINER.appendTo( + builder, + separatorWithDashes, + "Content-Disposition: form-data; name=\"" + element.getKey() + "\"", + "", + element.getValue(), + "" + ); + } + + builder.append(separatorWithDashes).append("--"); + + return builder.toString(); + } + + public String toUrlEncodedString() { + return URL_ENCODER.join( + elements.entrySet().stream() + .map(e -> Maps.immutableEntry( + UrlEscapers.urlFormParameterEscaper().escape(e.getKey()), + UrlEscapers.urlFormParameterEscaper().escape(e.getValue()) + )) + .iterator() + ); + } + + /** + * Create a new form. + * + * @return a new form + */ + public static Form create() { + return new Form(); + } + } + + /** + * Used to buffer the response in memory. + */ + public class BufferedResponse { + private final byte[] data; + + private BufferedResponse(byte[] data) { + this.data = data; + } + + /** + * Return the result as bytes. + * + * @return the data + */ + public byte[] asBytes() { + return data; + } + + /** + * Return the result as a string. + * + * @param encoding the encoding + * @return the string + * @throws IOException on I/O error + */ + public String asString(String encoding) throws IOException { + return new String(data, encoding); + } + + /** + * Save the result to a file. + * + * @param file the file + * @return this object + * @throws IOException on I/O error + * @throws InterruptedException on interruption + */ + public BufferedResponse saveContent(File file) throws IOException, InterruptedException { + Closer closer = Closer.create(); + file.getParentFile().mkdirs(); + + try { + FileOutputStream fos = closer.register(new FileOutputStream(file)); + BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos)); + + saveContent(bos); + } finally { + closer.close(); + } + + return this; + } + + /** + * Save the result to an output stream. + * + * @param out the output stream + * @return this object + * @throws IOException on I/O error + * @throws InterruptedException on interruption + */ + public BufferedResponse saveContent(OutputStream out) throws IOException, InterruptedException { + out.write(data); + + return this; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java b/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java new file mode 100644 index 0000000..5e9acaa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java @@ -0,0 +1,80 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.paste; + +import com.sk89q.worldedit.command.util.AsyncCommandBuilder; +import com.sk89q.worldedit.extension.platform.Actor; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.util.task.Supervisor; + +import java.net.URL; +import java.util.concurrent.Callable; + +public final class ActorCallbackPaste { + + private static final Paster paster = new EngineHubPaste(); + + private ActorCallbackPaste() { + } + + /** + * Submit data to a pastebin service and inform the sender of + * success or failure. + * + * @param supervisor The supervisor instance + * @param sender The sender + * @param content The content + * @param successMessage The message, formatted with {@link String#format(String, Object...)} on success + * @deprecated Use the Component-based version + */ + @Deprecated + public static void pastebin(Supervisor supervisor, final Actor sender, String content, final String successMessage) { + Callable task = paster.paste(content); + + AsyncCommandBuilder.wrap(task, sender) + .registerWithSupervisor(supervisor, "Submitting content to a pastebin service.") + .sendMessageAfterDelay("(Please wait... sending output to pastebin...)") + .onSuccess((String) null, url -> sender.print(String.format(successMessage, url))) + .onFailure("Failed to submit paste", null) + .buildAndExec(Pasters.getExecutor()); + } + + /** + * Submit data to a pastebin service and inform the sender of + * success or failure. + * + * @param supervisor The supervisor instance + * @param sender The sender + * @param content The content + * @param successMessage The message builder, given the URL as an arg + */ + public static void pastebin(Supervisor supervisor, final Actor sender, String content, final TranslatableComponent.Builder successMessage) { + Callable task = paster.paste(content); + + AsyncCommandBuilder.wrap(task, sender) + .registerWithSupervisor(supervisor, "Submitting content to a pastebin service.") + .setDelayMessage(TranslatableComponent.of("worldedit.pastebin.uploading")) + .onSuccess((String) null, url -> sender.printInfo(successMessage.args(TextComponent.of(url.toString())).build())) + .onFailure("Failed to submit paste", null) + .buildAndExec(Pasters.getExecutor()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java b/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java new file mode 100644 index 0000000..7416d8c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java @@ -0,0 +1,79 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.paste; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.sk89q.worldedit.util.net.HttpRequest; + +import java.io.IOException; +import java.net.URL; +import java.util.Map; +import java.util.concurrent.Callable; + +public class EngineHubPaste implements Paster { + + private static final Gson GSON = new Gson(); + + @Override + public Callable paste(String content) { + return new PasteTask(content); + } + + private static final class PasteTask implements Callable { + private final String content; + + private PasteTask(String content) { + this.content = content; + } + + @Override + public URL call() throws IOException, InterruptedException { + URL initialUrl = HttpRequest.url("https://paste.enginehub.org/signed_paste"); + + SignedPasteResponse response = GSON.fromJson(HttpRequest.get(initialUrl) + .execute() + .expectResponseCode(200) + .returnContent() + .asString("UTF-8"), TypeToken.get(SignedPasteResponse.class).getType()); + + HttpRequest.Form form = HttpRequest.Form.create(); + for (Map.Entry entry : response.uploadFields.entrySet()) { + form.add(entry.getKey(), entry.getValue()); + } + form.add("file", content); + + URL url = HttpRequest.url(response.uploadUrl); + // If this succeeds, it will not return any data aside from a 204 status. + HttpRequest.post(url) + .bodyMultipartForm(form) + .execute() + .expectResponseCode(200, 204); + + return new URL(response.viewUrl); + } + } + + private static final class SignedPasteResponse { + String viewUrl; + String uploadUrl; + Map uploadFields; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/paste/Paster.java b/src/main/java/com/sk89q/worldedit/util/paste/Paster.java new file mode 100644 index 0000000..0b7652b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/paste/Paster.java @@ -0,0 +1,29 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.paste; + +import java.net.URL; +import java.util.concurrent.Callable; + +public interface Paster { + + Callable paste(String content); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/paste/Pasters.java b/src/main/java/com/sk89q/worldedit/util/paste/Pasters.java new file mode 100644 index 0000000..430aac4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/paste/Pasters.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.paste; + +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +final class Pasters { + + private static final ListeningExecutorService executor = + MoreExecutors.listeningDecorator( + new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 2L, TimeUnit.SECONDS, + new SynchronousQueue<>())); + + private Pasters() { + } + + static ListeningExecutorService getExecutor() { + return executor; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/report/ConfigReport.java b/src/main/java/com/sk89q/worldedit/util/report/ConfigReport.java new file mode 100644 index 0000000..1393d38 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/report/ConfigReport.java @@ -0,0 +1,32 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.report; + +import com.sk89q.worldedit.WorldEdit; + +public class ConfigReport extends DataReport { + + public ConfigReport() { + super("WorldEdit Configuration"); + + append("Configuration", new HierarchyObjectReport("Configuration", WorldEdit.getInstance().getConfiguration())); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/report/DataReport.java b/src/main/java/com/sk89q/worldedit/util/report/DataReport.java new file mode 100644 index 0000000..a871c5f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/report/DataReport.java @@ -0,0 +1,181 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.report; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class DataReport implements Report { + + private final String title; + private final List lines = Lists.newArrayList(); + + public DataReport(String title) { + checkNotNull(title, "title"); + this.title = title; + } + + public void append(String key, String message) { + checkNotNull(key, "key"); + lines.add(new Line(key, message)); + } + + public void append(String key, String message, Object... values) { + checkNotNull(message, "values"); + checkNotNull(values, "values"); + append(key, String.format(message, values)); + } + + public void append(String key, byte value) { + append(key, String.valueOf(value)); + } + + public void append(String key, short value) { + append(key, String.valueOf(value)); + } + + public void append(String key, int value) { + append(key, String.valueOf(value)); + } + + public void append(String key, long value) { + append(key, String.valueOf(value)); + } + + public void append(String key, float value) { + append(key, String.valueOf(value)); + } + + public void append(String key, double value) { + append(key, String.valueOf(value)); + } + + public void append(String key, boolean value) { + append(key, String.valueOf(value)); + } + + public void append(String key, char value) { + append(key, String.valueOf(value)); + } + + public void append(String key, Object value) { + append(key, getStringValue(value, Sets.newHashSet())); + } + + private static String getStringValue(Object value, Set seen) { + if (seen.contains(value)) { + return ""; + } else { + seen.add(value); + } + + if (value instanceof Object[]) { + value = Arrays.asList(value); + } + + if (value instanceof Collection) { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for (Object entry : (Collection) value) { + if (first) { + first = false; + } else { + builder.append("\n"); + } + builder.append(getStringValue(entry, Sets.newHashSet(seen))); + } + return builder.toString(); + } else if (value instanceof Map) { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for (Map.Entry entry : ((Map) value).entrySet()) { + if (first) { + first = false; + } else { + builder.append("\n"); + } + + String key = getStringValue(entry.getKey(), Sets.newHashSet(seen)).replaceAll("[\r\n]", ""); + if (key.length() > 60) { + key = key.substring(0, 60) + "..."; + } + + builder + .append(key) + .append(": ") + .append(getStringValue(entry.getValue(), Sets.newHashSet(seen))); + } + return builder.toString(); + } else { + return String.valueOf(value); + } + } + + @Override + public String getTitle() { + return title; + } + + @Override + public String toString() { + if (!lines.isEmpty()) { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for (Line line : lines) { + if (first) { + first = false; + } else { + builder.append("\n"); + } + builder.append(line.key).append(": "); + if (line.value == null) { + builder.append("null"); + } else if (line.value.contains("\n")) { + builder.append("\n"); + builder.append(line.value.replaceAll("(?m)^", "\t")); + } else { + builder.append(line.value); + } + } + return builder.toString(); + } else { + return "No data."; + } + } + + private static class Line { + private final String key; + private final String value; + + public Line(String key, String value) { + this.key = key; + this.value = value; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/report/HierarchyObjectReport.java b/src/main/java/com/sk89q/worldedit/util/report/HierarchyObjectReport.java new file mode 100644 index 0000000..b2fff9e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/report/HierarchyObjectReport.java @@ -0,0 +1,32 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.report; + +public class HierarchyObjectReport extends ShallowObjectReport { + + public HierarchyObjectReport(String title, Object object) { + super(title, object); + + Class type = object.getClass(); + while ((type = type.getSuperclass()) != null) { + scanClass(object, type); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/report/Report.java b/src/main/java/com/sk89q/worldedit/util/report/Report.java new file mode 100644 index 0000000..06e7c84 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/report/Report.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.report; + +public interface Report { + + String getTitle(); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/report/ReportList.java b/src/main/java/com/sk89q/worldedit/util/report/ReportList.java new file mode 100644 index 0000000..7ee4b52 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/report/ReportList.java @@ -0,0 +1,186 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.report; + +import com.google.common.collect.Lists; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +public class ReportList implements Report, List { + + private final String title; + private final List reports = Lists.newArrayList(); + + public ReportList(String title) { + this.title = title; + } + + @Override + public String getTitle() { + return title; + } + + @Override + public int size() { + return reports.size(); + } + + @Override + public boolean isEmpty() { + return reports.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return reports.contains(o); + } + + @Override + public Iterator iterator() { + return reports.iterator(); + } + + @Override + public Object[] toArray() { + return reports.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return reports.toArray(a); + } + + @Override + public boolean add(Report report) { + return reports.add(report); + } + + @Override + public boolean remove(Object o) { + return reports.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return reports.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + return reports.addAll(c); + } + + @Override + public boolean addAll(int index, Collection c) { + return reports.addAll(index, c); + } + + @Override + public boolean removeAll(Collection c) { + return reports.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return reports.retainAll(c); + } + + @Override + public void clear() { + reports.clear(); + } + + @Override + public boolean equals(Object o) { + return reports.equals(o); + } + + @Override + public int hashCode() { + return reports.hashCode(); + } + + @Override + public Report get(int index) { + return reports.get(index); + } + + @Override + public Report set(int index, Report element) { + return reports.set(index, element); + } + + @Override + public void add(int index, Report element) { + reports.add(index, element); + } + + @Override + public Report remove(int index) { + return reports.remove(index); + } + + @Override + public int indexOf(Object o) { + return reports.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return reports.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return reports.listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return reports.listIterator(index); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return reports.subList(fromIndex, toIndex); + } + + @Override + public String toString() { + if (!reports.isEmpty()) { + StringBuilder builder = new StringBuilder(); + for (Report report : reports) { + builder.append("================================\n") + .append(report.getTitle()) + .append("\n================================") + .append("\n\n") + .append(report.toString()) + .append("\n\n"); + } + return builder.toString(); + } else { + return "No reports."; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/report/ShallowObjectReport.java b/src/main/java/com/sk89q/worldedit/util/report/ShallowObjectReport.java new file mode 100644 index 0000000..7f6bc27 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/report/ShallowObjectReport.java @@ -0,0 +1,60 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.report; + +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import org.apache.logging.log4j.Logger; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ShallowObjectReport extends DataReport { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + public ShallowObjectReport(String title, Object object) { + super(title); + checkNotNull(object, "object"); + + scanClass(object, object.getClass()); + } + + void scanClass(Object object, Class type) { + for (Field field : type.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + + if (field.getAnnotation(Unreported.class) != null) { + continue; + } + + field.setAccessible(true); + try { + Object value = field.get(object); + append(field.getName(), String.valueOf(value)); + } catch (IllegalAccessException e) { + LOGGER.warn("Failed to get value of '" + field.getName() + "' on " + type); + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/report/StackTraceReport.java b/src/main/java/com/sk89q/worldedit/util/report/StackTraceReport.java new file mode 100644 index 0000000..90ef9fe --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/report/StackTraceReport.java @@ -0,0 +1,64 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.report; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class StackTraceReport implements Report { + + private final StackTraceElement[] stackTrace; + + public StackTraceReport(StackTraceElement[] stackTrace) { + checkNotNull(stackTrace, "stackTrace"); + this.stackTrace = stackTrace; + } + + @Override + public String getTitle() { + return "Stack Trace"; + } + + @Override + public String toString() { + if (stackTrace.length > 0) { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for (StackTraceElement element : stackTrace) { + if (first) { + first = false; + } else { + builder.append("\n"); + } + builder.append(element.getClassName()) + .append(".") + .append(element.getMethodName()) + .append("() (") + .append(element.getFileName()) + .append(":") + .append(element.getLineNumber()) + .append(")"); + } + return builder.toString(); + } else { + return "No stack trace available."; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/report/SystemInfoReport.java b/src/main/java/com/sk89q/worldedit/util/report/SystemInfoReport.java new file mode 100644 index 0000000..ccb5d84 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/report/SystemInfoReport.java @@ -0,0 +1,97 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.report; + +import java.lang.management.ClassLoadingMXBean; +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; +import java.lang.management.RuntimeMXBean; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class SystemInfoReport extends DataReport { + + public SystemInfoReport() { + super("System Information"); + + Runtime runtime = Runtime.getRuntime(); + RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); + ClassLoadingMXBean classLoadingBean = ManagementFactory.getClassLoadingMXBean(); + List gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); + OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); + ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); + + append("Java", "%s %s (%s)", + System.getProperty("java.vendor"), + System.getProperty("java.version"), + System.getProperty("java.vendor.url")); + append("Operating System", "%s %s (%s)", + System.getProperty("os.name"), + System.getProperty("os.version"), + System.getProperty("os.arch")); + append("Available Processors", runtime.availableProcessors()); + append("Free Memory", runtime.freeMemory() / 1024 / 1024 + " MB"); + append("Max Memory", runtime.maxMemory() / 1024 / 1024 + " MB"); + append("Total Memory", runtime.totalMemory() / 1024 / 1024 + " MB"); + append("System Load Average", osBean.getSystemLoadAverage()); + append("Java Uptime", TimeUnit.MINUTES.convert(runtimeBean.getUptime(), TimeUnit.MILLISECONDS) + " minutes"); + + DataReport startup = new DataReport("Startup"); + startup.append("Input Arguments", runtimeBean.getInputArguments()); + append(startup.getTitle(), startup); + + DataReport vm = new DataReport("Virtual Machine"); + vm.append("Name", runtimeBean.getVmName()); + vm.append("Vendor", runtimeBean.getVmVendor()); + vm.append("Version", runtimeBean.getVmVendor()); + append(vm.getTitle(), vm); + + DataReport spec = new DataReport("Specification"); + spec.append("Name", runtimeBean.getSpecName()); + spec.append("Vendor", runtimeBean.getSpecVendor()); + spec.append("Version", runtimeBean.getSpecVersion()); + append(spec.getTitle(), spec); + + DataReport classLoader = new DataReport("Class Loader"); + classLoader.append("Loaded Class Count", classLoadingBean.getLoadedClassCount()); + classLoader.append("Total Loaded Class Count", classLoadingBean.getTotalLoadedClassCount()); + classLoader.append("Unloaded Class Count", classLoadingBean.getUnloadedClassCount()); + append(classLoader.getTitle(), classLoader); + + DataReport gc = new DataReport("Garbage Collectors"); + for (GarbageCollectorMXBean bean : gcBeans) { + DataReport thisGC = new DataReport(bean.getName()); + thisGC.append("Collection Count", bean.getCollectionCount()); + thisGC.append("Collection Time", bean.getCollectionTime() + "ms"); + gc.append(thisGC.getTitle(), thisGC); + } + append(gc.getTitle(), gc); + + DataReport threads = new DataReport("Threads"); + for (ThreadInfo threadInfo : threadBean.dumpAllThreads(false, false)) { + threads.append("#" + threadInfo.getThreadId() + " " + threadInfo.getThreadName(), threadInfo.getThreadState()); + } + append(threads.getTitle(), threads); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/report/Unreported.java b/src/main/java/com/sk89q/worldedit/util/report/Unreported.java new file mode 100644 index 0000000..db8e930 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/report/Unreported.java @@ -0,0 +1,33 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.report; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates properties that should not be exposed in the report. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Unreported { +} diff --git a/src/main/java/com/sk89q/worldedit/util/task/AbstractTask.java b/src/main/java/com/sk89q/worldedit/util/task/AbstractTask.java new file mode 100644 index 0000000..e8db229 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/task/AbstractTask.java @@ -0,0 +1,74 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.task; + +import com.google.common.util.concurrent.AbstractFuture; + +import javax.annotation.Nullable; +import java.util.Date; +import java.util.UUID; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An abstract task that stores a name and owner. + * + * @param the type returned + */ +public abstract class AbstractTask extends AbstractFuture implements Task { + + private final UUID uniqueId = UUID.randomUUID(); + private final String name; + private final Object owner; + private final Date creationDate = new Date(); + + /** + * Create a new instance. + * + * @param name the name + * @param owner the owner + */ + protected AbstractTask(String name, @Nullable Object owner) { + checkNotNull(name); + this.name = name; + this.owner = owner; + } + + @Override + public UUID getUniqueId() { + return uniqueId; + } + + @Override + public String getName() { + return name; + } + + @Nullable + @Override + public Object getOwner() { + return owner; + } + + @Override + public Date getCreationDate() { + return creationDate; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/task/FutureForwardingTask.java b/src/main/java/com/sk89q/worldedit/util/task/FutureForwardingTask.java new file mode 100644 index 0000000..a480dc6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/task/FutureForwardingTask.java @@ -0,0 +1,121 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.task; + +import com.google.common.util.concurrent.ListenableFuture; +import com.sk89q.worldedit.util.task.progress.Progress; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A task that wraps a {@code ListenableFuture}. + * + *

{@link State#SCHEDULED} is never returned because it is not possible + * to test whether the future has "started," so {@link State#RUNNING} is + * returned in its place.

+ * + *

Use {@link #create(ListenableFuture, String, Object)} to create a new + * instance.

+ * + * @param the type returned + */ +public class FutureForwardingTask extends AbstractTask { + + private final ListenableFuture future; + + private FutureForwardingTask(ListenableFuture future, String name, @Nullable Object owner) { + super(name, owner); + checkNotNull(future); + this.future = future; + } + + @Override + public void addListener(Runnable listener, Executor executor) { + future.addListener(listener, executor); + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return future.cancel(mayInterruptIfRunning); + } + + @Override + public boolean isCancelled() { + return future.isCancelled(); + } + + @Override + public boolean isDone() { + return future.isDone(); + } + + @Override + public V get() throws InterruptedException, ExecutionException { + return future.get(); + } + + @Override + public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return future.get(timeout, unit); + } + + @Override + public State getState() { + if (isCancelled()) { + return State.CANCELLED; + } else if (isDone()) { + try { + get(); + return State.SUCCEEDED; + } catch (InterruptedException e) { + return State.CANCELLED; + } catch (ExecutionException e) { + return State.FAILED; + } + } else { + return State.RUNNING; + } + } + + @Override + public Progress getProgress() { + return Progress.indeterminate(); + } + + /** + * Create a new instance. + * + * @param future the future + * @param name the name of the task + * @param owner the owner of the task, or {@code null} + * @param the type returned by the future + * @return a new instance + */ + public static FutureForwardingTask create(ListenableFuture future, String name, @Nullable Object owner) { + return new FutureForwardingTask<>(future, name, owner); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/task/SimpleSupervisor.java b/src/main/java/com/sk89q/worldedit/util/task/SimpleSupervisor.java new file mode 100644 index 0000000..7799b21 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/task/SimpleSupervisor.java @@ -0,0 +1,59 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.task; + +import com.google.common.util.concurrent.MoreExecutors; + +import java.util.ArrayList; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An implementation of a {@code Supervisor}. + */ +public class SimpleSupervisor implements Supervisor { + + private final List> monitored = new ArrayList<>(); + private final Object lock = new Object(); + + @Override + public List> getTasks() { + synchronized (lock) { + return new ArrayList<>(monitored); + } + } + + @Override + public void monitor(final Task task) { + checkNotNull(task); + + synchronized (lock) { + monitored.add(task); + } + + task.addListener(() -> { + synchronized (lock) { + monitored.remove(task); + } + }, MoreExecutors.directExecutor()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/task/Supervisor.java b/src/main/java/com/sk89q/worldedit/util/task/Supervisor.java new file mode 100644 index 0000000..a01ad74 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/task/Supervisor.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.task; + +import java.util.List; + +/** + * Manages running tasks and informs users of their progress, but does not + * execute the task. + */ +public interface Supervisor { + + /** + * Get a list of running or queued tasks. + * + * @return a list of tasks + */ + List> getTasks(); + + /** + * Monitor the given task. + * + * @param task the task + */ + void monitor(Task task); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/task/Task.java b/src/main/java/com/sk89q/worldedit/util/task/Task.java new file mode 100644 index 0000000..fd26c26 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/task/Task.java @@ -0,0 +1,97 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.task; + +import com.google.common.util.concurrent.ListenableFuture; +import com.sk89q.worldedit.util.task.progress.ProgressObservable; + +import javax.annotation.Nullable; +import java.util.Date; +import java.util.UUID; + +/** + * A task is a job that can be scheduled, run, or cancelled. Tasks can report + * on their own status. Tasks have owners. + */ +public interface Task extends ListenableFuture, ProgressObservable { + + /** + * Get the unique ID of this task. + * + * @return this task's unique ID + */ + UUID getUniqueId(); + + /** + * Get the name of the task so it can be printed to the user. + * + * @return the name of the task + */ + String getName(); + + /** + * Get the owner of the task. + * + * @return an owner object, if one is known or valid, otherwise {@code null} + */ + @Nullable + Object getOwner(); + + /** + * Get the state of the task. + * + * @return the state of the task + */ + State getState(); + + /** + * Get the time at which the task was created. + * + * @return a date + */ + Date getCreationDate(); + + /** + * Represents the state of a task. + */ + enum State { + /** + * The task has been scheduled to run but is not running yet. + */ + SCHEDULED, + /** + * The task has been cancelled and may be stopped or will stop. + */ + CANCELLED, + /** + * The task is currently running. + */ + RUNNING, + /** + * The task has failed. + */ + FAILED, + /** + * The task has succeeded. + */ + SUCCEEDED + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/task/TaskStateComparator.java b/src/main/java/com/sk89q/worldedit/util/task/TaskStateComparator.java new file mode 100644 index 0000000..298ec8f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/task/TaskStateComparator.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.task; + +import java.util.Comparator; + +/** + * Compares task states according to the order of the {@link Task.State} + * enumeration. + */ +public class TaskStateComparator implements Comparator> { + + @Override + public int compare(Task o1, Task o2) { + int ordinal1 = o1.getState().ordinal(); + int ordinal2 = o2.getState().ordinal(); + if (ordinal1 < ordinal2) { + return -1; + } else if (ordinal1 > ordinal2) { + return 1; + } else { + return 0; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/task/progress/Progress.java b/src/main/java/com/sk89q/worldedit/util/task/progress/Progress.java new file mode 100644 index 0000000..965aad1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/task/progress/Progress.java @@ -0,0 +1,183 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.task.progress; + +import java.util.Arrays; +import java.util.Collection; + +/** + * A progress object describes the progress of an operation, specifying + * either a percentage of completion or a status of indeterminacy. + * + *

Progress objects are immutable.

+ * + *

To create a new instance, use one of the static constructors + * on this class.

+ */ +public abstract class Progress { + + /** + * Create a new instance. + */ + private Progress() { + } + + /** + * Return whether the current progress is indeterminate. + * + * @return true if indeterminate + */ + public abstract boolean isIndeterminate(); + + /** + * Get the progress percentage. + * + *

If {@link #isIndeterminate()} returns {@code true}, the behavior + * of this method is undefined.

+ * + * @return a number in the range [0, 1] + */ + public abstract double getProgress(); + + /** + * Get a static progress object that is indeterminate. + * + * @return a progress object + */ + public static Progress indeterminate() { + return INDETERMINATE; + } + + /** + * Get a static progress object that is complete. + * + * @return a progress object + */ + public static Progress completed() { + return COMPLETED; + } + + /** + * Create a new progress object with the given percentage. + * + * @param value the percentage, which will be clamped to [0, 1] + * @return a progress object + */ + public static Progress of(double value) { + if (value < 0) { + value = 0; + } else if (value > 1) { + value = 1; + } + + final double finalValue = value; + return new Progress() { + @Override + public boolean isIndeterminate() { + return false; + } + + @Override + public double getProgress() { + return finalValue; + } + }; + } + + /** + * Create a new progress object with progress split equally between the + * given progress objects. + * + * @param objects an array of progress objects + * @return a new progress value + */ + public static Progress split(Progress... objects) { + return split(Arrays.asList(objects)); + } + + /** + * Create a new progress object with progress split equally between the + * given progress objects. + * + * @param progress a collection of progress objects + * @return a new progress value + */ + public static Progress split(Collection progress) { + int count = 0; + double total = 0; + + for (Progress p : progress) { + if (p.isIndeterminate()) { + return indeterminate(); + } + total += p.getProgress(); + } + + return of(total / count); + } + + /** + * Create a new progress object with progress split equally between the + * given {@link ProgressObservable}s. + * + * @param observables an array of observables + * @return a new progress value + */ + public static Progress splitObservables(ProgressObservable... observables) { + return splitObservables(Arrays.asList(observables)); + } + + /** + * Create a new progress object with progress split equally between the + * given {@link ProgressObservable}s. + * + * @param observables a collection of observables + * @return a new progress value + */ + public static Progress splitObservables(Collection observables) { + int count = 0; + double total = 0; + + for (ProgressObservable observable : observables) { + Progress p = observable.getProgress(); + if (p.isIndeterminate()) { + return indeterminate(); + } + total += p.getProgress(); + } + + return of(total / count); + } + + private static final Progress COMPLETED = of(1); + + private static final Progress INDETERMINATE = new Progress() { + @Override + public boolean isIndeterminate() { + return true; + } + + @Override + public double getProgress() { + return 0; + } + }; + +} diff --git a/src/main/java/com/sk89q/worldedit/util/task/progress/ProgressIterator.java b/src/main/java/com/sk89q/worldedit/util/task/progress/ProgressIterator.java new file mode 100644 index 0000000..26ceb12 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/task/progress/ProgressIterator.java @@ -0,0 +1,100 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.task.progress; + +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An iterator that keeps track of how many entries have been visited and + * calculates a "percent completed" using a provided total count. + * + *

The returned progress percentage will always be between 0 or 1 + * (inclusive). If the iterator returns more entries than the total count, + * then 100% will be returned for the progress.

+ * + * @param the type + */ +public class ProgressIterator implements Iterator, ProgressObservable { + + private final Iterator iterator; + private final int count; + private int visited = 0; + + /** + * Create a new instance. + * + * @param iterator the iterator + * @param count the count + */ + private ProgressIterator(Iterator iterator, int count) { + checkNotNull(iterator); + this.iterator = iterator; + this.count = count; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public V next() { + V value = iterator.next(); + visited++; + return value; + } + + @Override + public void remove() { + iterator.remove(); + } + + @Override + public Progress getProgress() { + return Progress.of(count > 0 ? Math.min(1, Math.max(0, (visited / (double) count))) : 1); + } + + /** + * Create a new instance. + * + * @param iterator the iterator + * @param count the number of objects + * @param the type + * @return an instance + */ + public static ProgressIterator create(Iterator iterator, int count) { + return new ProgressIterator(iterator, count); + } + + /** + * Create a new instance from a list. + * + * @param list a list + * @param the type + * @return an instance + */ + public static ProgressIterator create(List list) { + return create(list.iterator(), list.size()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/task/progress/ProgressObservable.java b/src/main/java/com/sk89q/worldedit/util/task/progress/ProgressObservable.java new file mode 100644 index 0000000..60b9839 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/task/progress/ProgressObservable.java @@ -0,0 +1,34 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.task.progress; + +/** + * An object that is able to report on its progress. + */ +public interface ProgressObservable { + + /** + * Get the current percentage of completion. + * + * @return a progress object + */ + Progress getProgress(); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/time/FileNameDateTimeParser.java b/src/main/java/com/sk89q/worldedit/util/time/FileNameDateTimeParser.java new file mode 100644 index 0000000..c741067 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/time/FileNameDateTimeParser.java @@ -0,0 +1,108 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.time; + +import com.google.common.collect.Streams; +import com.sk89q.worldedit.util.io.file.MorePaths; + +import javax.annotation.Nullable; +import java.nio.file.Path; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.StreamSupport; + +/** + * Parses date-times by looking at the file name. File names without a time + * will use 00:00:00. + * + *

+ * Elements may be separated by a space, dash, or colon. + * The date and time may additionally be separated by a 'T'. + * Only the year must have all digits, others may omit padding + * zeroes. + *

+ * + *

+ * Valid file name examples: + *

    + *
  • {@code 2019-06-15}
  • + *
  • {@code 2019-06-15 10:20:30}
  • + *
  • {@code 2019-06-15 10:20:30}
  • + *
  • {@code 2019-06-15T10:20:30}
  • + *
  • {@code 2019 06 15 10 20 30}
  • + *
  • {@code 2019-06-15-10-20-30}
  • + *
  • {@code 2019-6-1-1-2-3}
  • + *
+ *

+ */ +public class FileNameDateTimeParser implements SnapshotDateTimeParser { + + private static final FileNameDateTimeParser INSTANCE = new FileNameDateTimeParser(); + + public static FileNameDateTimeParser getInstance() { + return INSTANCE; + } + + private static final String SEP = "[ \\-_:]"; + + private static final Pattern BASIC_FILTER = Pattern.compile( + "^(?\\d{4})" + SEP + "(?\\d{1,2})" + SEP + "(?\\d{1,2})" + // Optionally: + + "(?:" + "[ \\-_:T]" + + "(?\\d{1,2})" + SEP + "(?\\d{1,2})" + SEP + "(?\\d{1,2})" + + ")?" + ); + + private FileNameDateTimeParser() { + } + + @Nullable + @Override + public ZonedDateTime detectDateTime(Path path) { + // Make this perform a little better: + Matcher matcher = Streams.findLast( + StreamSupport.stream(MorePaths.optimizedSpliterator(path), false) + .map(p -> BASIC_FILTER.matcher(p.toString())) + .filter(Matcher::find) + ).orElse(null); + if (matcher != null) { + int year = matchAndParseOrZero(matcher, "year"); + int month = matchAndParseOrZero(matcher, "month"); + int day = matchAndParseOrZero(matcher, "day"); + int hour = matchAndParseOrZero(matcher, "hour"); + int minute = matchAndParseOrZero(matcher, "minute"); + int second = matchAndParseOrZero(matcher, "second"); + return ZonedDateTime.of(year, month, day, hour, minute, second, + 0, ZoneId.systemDefault()); + } + return null; + } + + private static int matchAndParseOrZero(Matcher matcher, String group) { + String match = matcher.group(group); + if (match == null) { + return 0; + } + return Integer.parseInt(match); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/time/ModificationDateTimeParser.java b/src/main/java/com/sk89q/worldedit/util/time/ModificationDateTimeParser.java new file mode 100644 index 0000000..7d8264d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/time/ModificationDateTimeParser.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.time; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +public class ModificationDateTimeParser implements SnapshotDateTimeParser { + + private static final ModificationDateTimeParser INSTANCE = new ModificationDateTimeParser(); + + public static ModificationDateTimeParser getInstance() { + return INSTANCE; + } + + private ModificationDateTimeParser() { + } + + @Override + public ZonedDateTime detectDateTime(Path path) { + if (!Files.exists(path)) { + return null; + } + try { + return Files.getLastModifiedTime(path).toInstant().atZone(ZoneId.systemDefault()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/time/SnapshotDateTimeParser.java b/src/main/java/com/sk89q/worldedit/util/time/SnapshotDateTimeParser.java new file mode 100644 index 0000000..fad3bfb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/time/SnapshotDateTimeParser.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.time; + +import java.nio.file.Path; +import java.time.ZonedDateTime; +import javax.annotation.Nullable; + +/** + * Instances of this interface try to determine an {@link ZonedDateTime} from a given + * {@link Path}. + */ +public interface SnapshotDateTimeParser { + + /** + * Attempt to detect an ZonedDateTime from a path. + * + *

+ * The path is not guaranteed to exist. + *

+ * + * @param path the path + * @return date-time, if it can be parsed + */ + @Nullable + ZonedDateTime detectDateTime(Path path); + +} diff --git a/src/main/java/com/sk89q/worldedit/util/translation/TranslationManager.java b/src/main/java/com/sk89q/worldedit/util/translation/TranslationManager.java new file mode 100644 index 0000000..9001ead --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/translation/TranslationManager.java @@ -0,0 +1,274 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.util.translation; + +import com.google.common.collect.Sets; +import com.google.common.collect.Table; +import com.google.common.collect.Tables; +import com.google.common.util.concurrent.Futures; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import net.kyori.text.Component; +import net.kyori.text.renderer.TranslatableComponentRenderer; +import com.sk89q.worldedit.util.io.ResourceLoader; +import com.sk89q.worldedit.util.io.file.ArchiveUnpacker; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UncheckedIOException; +import java.lang.reflect.Type; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Future; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Handles translations for the plugin. + * + *

+ * These should be in the following format: + * plugin.component.message[.meta]* + *

+ * + *

+ * Where, + * plugin = worldedit + * component = The part of the plugin, eg expand + * message = A descriptor for which message, eg, expanded + * meta = Any extra information such as plural/singular (Can have none to infinite) + *

+ */ +public class TranslationManager { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final Gson GSON = new GsonBuilder().create(); + private static final Type STRING_MAP_TYPE = new TypeToken>() { + }.getType(); + + public static String makeTranslationKey(String type, String id) { + String[] parts = id.split(":", 2); + return type + '.' + parts[0] + '.' + parts[1].replace('/', '.'); + } + + private final TranslatableComponentRenderer friendlyComponentRenderer = TranslatableComponentRenderer.from( + this::getTranslation + ); + private final Table translationTable = Tables.newCustomTable( + new ConcurrentHashMap<>(), ConcurrentHashMap::new + ); + private final Map> loadFutures = new HashMap<>(); + private final Set loadedLocales = Sets.newConcurrentHashSet(); + private final Lock loadLock = new ReentrantLock(); + private Locale defaultLocale = Locale.ENGLISH; + + private final ArchiveUnpacker archiveUnpacker; + private final ResourceLoader resourceLoader; + private final Path userProvidedFlatRoot; + private final Path internalZipRoot; + @Nullable + private Path userProvidedZipRoot; + + public TranslationManager(ArchiveUnpacker archiveUnpacker, ResourceLoader resourceLoader) throws IOException { + this.archiveUnpacker = archiveUnpacker; + this.resourceLoader = resourceLoader; + checkNotNull(resourceLoader); + this.userProvidedFlatRoot = resourceLoader.getLocalResource("lang"); + this.internalZipRoot = archiveUnpacker.unpackArchive(checkNotNull( + resourceLoader.getRootResource("lang/i18n.zip"), + "Missing internal i18n.zip!" + )); + } + + private void load() throws IOException { + Path userZip = resourceLoader.getLocalResource("lang/i18n.zip"); + Path result = null; + if (Files.exists(userZip)) { + result = archiveUnpacker.unpackArchive(userZip.toUri().toURL()); + } + this.userProvidedZipRoot = result; + } + + public void reload() { + loadLock.lock(); + try { + loadedLocales.clear(); + for (Future future : loadFutures.values()) { + Futures.getUnchecked(future); + } + loadFutures.clear(); + translationTable.clear(); + load(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } finally { + loadLock.unlock(); + } + } + + public Component convertText(Component component, Locale locale) { + return friendlyComponentRenderer.render(component, locale); + } + + public void setDefaultLocale(Locale defaultLocale) { + this.defaultLocale = defaultLocale; + } + + private MessageFormat getTranslation(Locale locale, String key) { + if (!loadedLocales.contains(locale)) { + loadLocale(locale); + } + + MessageFormat format = translationTable.get(locale, key); + if (format == null && !defaultLocale.equals(locale)) { + // Recurse into other options if not already at the base condition (defaultLocale) + if (!locale.getCountry().isEmpty()) { + // try without country modifier + return getTranslation(new Locale(locale.getLanguage()), key); + } + // otherwise, try the default locale + return getTranslation(defaultLocale, key); + } + // note that this may be null in the case of the defaultLocale + return format; + } + + private void loadLocale(Locale locale) { + CompletableFuture ourFuture; + loadLock.lock(); + try { + Future ftr = loadFutures.get(locale); + if (ftr == null) { + // no existing future, enter ourselves as the loader + ourFuture = new CompletableFuture<>(); + loadFutures.put(locale, ourFuture); + } else { + // existing loader, await their completion first + Futures.getUnchecked(ftr); + return; + } + } finally { + loadLock.unlock(); + } + + try { + loadTranslations(locale); + } catch (Exception t) { + LOGGER.warn( + "Failed to load translations" + + ", locale=" + locale, + t + ); + } finally { + ourFuture.complete(null); + loadedLocales.add(locale); + } + } + + private void loadTranslations(Locale locale) throws IOException { + Map entries = new HashMap<>(); + + String localePath = getLocalePath(locale); + // From lowest priority to highest + if (defaultLocale.equals(locale)) { + // load internal strings, not i18n.zip + // we need this for development and to ensure translations are at least minimally + // working in the case of no i18n.zip update + URL internalStrings = resourceLoader.getRootResource("lang/strings.json"); + checkNotNull(internalStrings, "Failed to load internal strings.json"); + try (InputStream in = internalStrings.openStream()) { + putTranslationData(entries, in); + } + } else { + // load from the internal zip for all other locales + putTranslationData(entries, this.internalZipRoot.resolve(localePath)); + } + if (this.userProvidedZipRoot != null) { + putTranslationData(entries, this.userProvidedZipRoot.resolve(localePath)); + } + putTranslationData(entries, this.userProvidedFlatRoot.resolve(localePath)); + + // Load message formats + for (Map.Entry entry : entries.entrySet()) { + MessageFormat format; + try { + format = new MessageFormat(entry.getValue().replace("'", "''"), locale); + } catch (IllegalArgumentException e) { + LOGGER.warn( + "Failed to load translation" + + ", locale=" + locale + + ", key=" + entry.getKey() + + ", value=" + entry.getValue(), + e + ); + continue; + } + translationTable.put( + locale, entry.getKey(), format + ); + } + } + + private String getLocalePath(Locale locale) { + if (defaultLocale.equals(locale)) { + return "strings.json"; + } + String country = locale.getCountry().isEmpty() ? "" : "-" + locale.getCountry(); + return locale.getLanguage() + country + "/strings.json"; + } + + private void putTranslationData(Map data, Path source) throws IOException { + if (!Files.exists(source)) { + return; + } + try (InputStream in = Files.newInputStream(source)) { + putTranslationData(data, in); + } + } + + private void putTranslationData(Map data, InputStream inputStream) throws IOException { + try (Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { + Map map = GSON.fromJson(reader, STRING_MAP_TYPE); + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().isEmpty()) { + continue; + } + data.put(entry.getKey(), entry.getValue()); + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java new file mode 100644 index 0000000..01a0cc9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -0,0 +1,185 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.function.mask.BlockTypeMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.weather.WeatherType; +import com.sk89q.worldedit.world.weather.WeatherTypes; + +import java.nio.file.Path; +import java.util.PriorityQueue; +import javax.annotation.Nullable; + +/** + * An abstract implementation of {@link World}. + */ +public abstract class AbstractWorld implements World { + + private final PriorityQueue effectQueue = new PriorityQueue<>(); + private int taskId = -1; + + @Override + public boolean useItem(BlockVector3 position, BaseItem item, Direction face) { + return false; + } + + @Override + public final > boolean setBlock(BlockVector3 pt, B block) throws WorldEditException { + return setBlock(pt, block, SideEffectSet.defaults()); + } + + @Override + public Path getStoragePath() { + return null; + } + + @Override + public int getMinY() { + return 0; + } + + @Override + public int getMaxY() { + return 255; + } + + @Override + public Mask createLiquidMask() { + return new BlockTypeMask(this, BlockTypes.LAVA, BlockTypes.WATER); + } + + @Override + public void dropItem(Vector3 pt, BaseItemStack item, int times) { + for (int i = 0; i < times; ++i) { + dropItem(pt, item); + } + } + + @Override + public void checkLoadedChunk(BlockVector3 pt) { + } + + @Override + public void fixAfterFastMode(Iterable chunks) { + } + + @Override + public void fixLighting(Iterable chunks) { + } + + @Override + public boolean playEffect(Vector3 position, int type, int data) { + return false; + } + + @Override + public boolean queueBlockBreakEffect(Platform server, BlockVector3 position, BlockType blockType, double priority) { + if (taskId == -1) { + taskId = server.schedule(0, 1, () -> { + int max = Math.max(1, Math.min(30, effectQueue.size() / 3)); + for (int i = 0; i < max; ++i) { + if (effectQueue.isEmpty()) { + return; + } + + effectQueue.poll().play(); + } + }); + } + + if (taskId == -1) { + return false; + } + + effectQueue.offer(new QueuedEffect(position.toVector3(), blockType, priority)); + + return true; + } + + @Override + public BlockVector3 getMinimumPoint() { + return BlockVector3.at(-30000000, getMinY(), -30000000); + } + + @Override + public BlockVector3 getMaximumPoint() { + return BlockVector3.at(30000000, getMaxY(), 30000000); + } + + @Override + public @Nullable Operation commit() { + return null; + } + + @Override + public WeatherType getWeather() { + return WeatherTypes.CLEAR; + } + + @Override + public long getRemainingWeatherDuration() { + return 0; + } + + @Override + public void setWeather(WeatherType weatherType) { + } + + @Override + public void setWeather(WeatherType weatherType, long duration) { + } + + private class QueuedEffect implements Comparable { + private final Vector3 position; + private final BlockType blockType; + private final double priority; + + private QueuedEffect(Vector3 position, BlockType blockType, double priority) { + this.position = position; + this.blockType = blockType; + this.priority = priority; + } + + @SuppressWarnings("deprecation") + public void play() { + playEffect(position, 2001, blockType.getLegacyId()); + } + + @Override + public int compareTo(@Nullable QueuedEffect other) { + return Double.compare(priority, other != null ? other.priority : 0); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/DataException.java b/src/main/java/com/sk89q/worldedit/world/DataException.java new file mode 100644 index 0000000..d4f1235 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/DataException.java @@ -0,0 +1,35 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world; + +/** + * Thrown when there is an exception related to data handling. + */ +public class DataException extends Exception { + + public DataException(String msg) { + super(msg); + } + + public DataException() { + super(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/DataFixer.java b/src/main/java/com/sk89q/worldedit/world/DataFixer.java new file mode 100644 index 0000000..92176ab --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/DataFixer.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world; + +import com.google.common.annotations.Beta; +import com.sk89q.jnbt.CompoundTag; + +/** + * This entire class is subject to heavy changes. Do not use this as API. + */ +@Beta +public interface DataFixer { + + final class FixType { + private FixType() { + } + } + + final class FixTypes { + private FixTypes() { + } + + public static FixType CHUNK = new FixType<>(); + public static FixType BLOCK_ENTITY = new FixType<>(); + public static FixType ENTITY = new FixType<>(); + public static FixType BLOCK_STATE = new FixType<>(); + public static FixType BIOME = new FixType<>(); + public static FixType ITEM_TYPE = new FixType<>(); + } + + default T fixUp(FixType type, T original) { + return fixUp(type, original, -1); + } + + T fixUp(FixType type, T original, int srcVer); +} diff --git a/src/main/java/com/sk89q/worldedit/world/NbtValued.java b/src/main/java/com/sk89q/worldedit/world/NbtValued.java new file mode 100644 index 0000000..86ea9b4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/NbtValued.java @@ -0,0 +1,63 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world; + +import com.sk89q.jnbt.CompoundTag; + +import javax.annotation.Nullable; + +/** + * Indicates an object that contains extra data identified as an NBT structure. + * This interface is used when saving and loading objects to a serialized + * format, but may be used in other cases. + */ +public interface NbtValued { + + /** + * Returns whether the block contains NBT data. {@link #getNbtData()} + * must not return null if this method returns true. + * + * @return true if there is NBT data + */ + boolean hasNbtData(); + + /** + * Get the object's NBT data (tile entity data). The returned tag, if + * modified in any way, should be sent to {@link #setNbtData(CompoundTag)} + * so that the instance knows of the changes. Making changes without + * calling {@link #setNbtData(CompoundTag)} could have unintended + * consequences. + * + *

{@link #hasNbtData()} must return true if and only if method does + * not return null.

+ * + * @return compound tag, or null + */ + @Nullable + CompoundTag getNbtData(); + + /** + * Set the object's NBT data (tile entity data). + * + * @param nbtData NBT data, or null if no data + */ + void setNbtData(@Nullable CompoundTag nbtData); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/src/main/java/com/sk89q/worldedit/world/NullWorld.java new file mode 100644 index 0000000..419fb08 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -0,0 +1,184 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world; + +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.TreeGenerator.TreeType; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.weather.WeatherType; +import com.sk89q.worldedit.world.weather.WeatherTypes; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * A null implementation of {@link World} that drops all changes and + * returns dummy data. + */ +public class NullWorld extends AbstractWorld { + + private static final NullWorld INSTANCE = new NullWorld(); + + protected NullWorld() { + } + + @Override + public String getName() { + return "null"; + } + + @Override + public String getId() { + return "null"; + } + + @Override + public > boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException { + return false; + } + + @Override + public Set applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) + throws WorldEditException { + return ImmutableSet.of(); + } + + @Override + public int getBlockLightLevel(BlockVector3 position) { + return 0; + } + + @Override + public boolean clearContainerBlockContents(BlockVector3 position) { + return false; + } + + @Override + public boolean fullySupports3DBiomes() { + return false; + } + + @Override + public BiomeType getBiome(BlockVector3 position) { + return BiomeTypes.THE_VOID; + } + + @Override + public boolean setBiome(BlockVector3 position, BiomeType biome) { + return false; + } + + @Override + public void dropItem(Vector3 position, BaseItemStack item) { + } + + @Override + public void simulateBlockMine(BlockVector3 position) { + } + + @Override + public boolean regenerate(Region region, Extent extent, RegenOptions options) { + return false; + } + + @Override + public boolean generateTree(TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException { + return false; + } + + @Override + public WeatherType getWeather() { + return WeatherTypes.CLEAR; + } + + @Override + public long getRemainingWeatherDuration() { + return 0; + } + + @Override + public void setWeather(WeatherType weatherType) { + } + + @Override + public void setWeather(WeatherType weatherType, long duration) { + } + + @Override + public BlockVector3 getSpawnPosition() { + return BlockVector3.ZERO; + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return BlockTypes.AIR.getDefaultState(); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return getBlock(position).toBaseBlock(); + } + + @Override + public List getEntities(Region region) { + return Collections.emptyList(); + } + + @Override + public List getEntities() { + return Collections.emptyList(); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + return null; + } + + /** + * Return an instance of this null world. + * + * @return a null world + */ + public static NullWorld getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/RegenOptions.java b/src/main/java/com/sk89q/worldedit/world/RegenOptions.java new file mode 100644 index 0000000..17a0cd6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/RegenOptions.java @@ -0,0 +1,102 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world; + +import com.google.auto.value.AutoValue; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; +import java.util.OptionalLong; + +/** + * Regeneration options for {@link World#regenerate(Region, Extent, RegenOptions)}. + */ +@AutoValue +public abstract class RegenOptions { + + /** + * Creates a new options builder. + * + * @return the builder + */ + public static Builder builder() { + return new AutoValue_RegenOptions.Builder().seed(OptionalLong.empty()).regenBiomes(false); + } + + @AutoValue.Builder + public abstract static class Builder { + + /** + * Sets the seed to regenerate with. Defaults to {@code null}. + * + *

+ * Use {@code null} to use the world's current seed. + *

+ * + * @param seed the seed to regenerate with + * @return this builder + */ + public final Builder seed(@Nullable Long seed) { + return seed(seed == null ? OptionalLong.empty() : OptionalLong.of(seed)); + } + + // AV doesn't like us using @Nullable Long for some reason + abstract Builder seed(OptionalLong seed); + + /** + * Turn on or off applying the biomes from the regenerated chunk. Defaults to {@code false}. + * + * @param regenBiomes {@code true} to apply biomes + * @return this builder + */ + public abstract Builder regenBiomes(boolean regenBiomes); + + /** + * Build the options object. + * + * @return the options object + */ + public abstract RegenOptions build(); + + } + + RegenOptions() { + } + + /** + * The seed to regenerate with. + * + *

+ * {@link OptionalLong#empty()} if the world's original seed should be used. + *

+ */ + public abstract OptionalLong getSeed(); + + abstract boolean isRegenBiomes(); + + /** + * Whether biomes should be regenerated. + */ + public final boolean shouldRegenBiomes() { + return isRegenBiomes(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/World.java b/src/main/java/com/sk89q/worldedit/world/World.java new file mode 100644 index 0000000..276b206 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/World.java @@ -0,0 +1,366 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.weather.WeatherType; + +import java.nio.file.Path; +import java.util.Set; +import javax.annotation.Nullable; + +/** + * Represents a world (dimension). + */ +public interface World extends Extent, Keyed { + + /** + * Get the name of the world. + * + * @return a name for the world + */ + String getName(); + + /** + * Get the folder in which this world is stored. May return null if unknown + * or if this world is not serialized to disk. + * + * @return world storage path + */ + @Nullable + Path getStoragePath(); + + /** + * Get the minimum Y. + * + * @return the minimum Y + */ + int getMinY(); + + /** + * Get the maximum Y. + * + * @return the maximum Y + */ + int getMaxY(); + + /** + * Create a mask that matches all liquids. + * + *

Implementations should override this so that custom liquids + * are supported.

+ * + * @return a mask + */ + Mask createLiquidMask(); + + /** + * Use the given item on the block at the given location on the given side. + * + * @param item The item + * @param face The face + * @return Whether it succeeded + */ + boolean useItem(BlockVector3 position, BaseItem item, Direction face); + + /** + * Similar to {@link Extent#setBlock(BlockVector3, BlockStateHolder)} but a + * {@code notifyAndLight} parameter indicates whether adjacent blocks + * should be notified that changes have been made and lighting operations + * should be executed. + * + *

If it's not possible to skip lighting, or if it's not possible to + * avoid notifying adjacent blocks, then attempt to meet the + * specification as best as possible.

+ * + *

On implementations where the world is not simulated, the + * {@code notifyAndLight} parameter has no effect either way.

+ * + * @param position position of the block + * @param block block to set + * @param notifyAndLight true to to notify and light + * @return true if the block was successfully set (return value may not be accurate) + */ + @Deprecated + default > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { + return setBlock(position, block, notifyAndLight ? SideEffectSet.defaults() : SideEffectSet.none()); + } + + /** + * Similar to {@link Extent#setBlock(BlockVector3, BlockStateHolder)} but a + * {@code sideEffects} parameter indicates which side effects should be applied + * to the block. This includes block updates, lighting, and others. See {@link SideEffect} + * for a full list. + * + *

Not all implementations support all side effects. Use + * {@link Platform#getSupportedSideEffects()} for a list of supported side effects. + * Non-supported side effects will be ignored.

+ * + * @param position position of the block + * @param block block to set + * @param sideEffects which side effects to perform + * @return true if the block was successfully set (return value may not be accurate) + */ + > boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException; + + /** + * Notifies the simulation that the block at the given location has + * been changed and it must be re-lighted (and issue other events). + * + * @param position position of the block + * @param previousType the type of the previous block that was there + * @return true if the block was successfully notified + */ + @Deprecated + default boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { + return !applySideEffects(position, previousType, SideEffectSet.defaults()).isEmpty(); + } + + /** + * Applies a set of side effects on the given block. + * + * @param position position of the block + * @param previousType the type of the previous block that was there + * @param sideEffectSet which side effects to perform + * @return a set of side effects that were applied + */ + Set applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) throws WorldEditException; + + /** + * Get the light level at the given block. + * + * @param position the position + * @return the light level (0-15) + */ + int getBlockLightLevel(BlockVector3 position); + + /** + * Clear a chest's contents. + * + * @param position the position + * @return true if the container was cleared + */ + boolean clearContainerBlockContents(BlockVector3 position); + + /** + * Drop an item at the given position. + * + * @param position the position + * @param item the item to drop + * @param count the number of individual stacks to drop (number of item entities) + */ + void dropItem(Vector3 position, BaseItemStack item, int count); + + /** + * Drop one stack of the item at the given position. + * + * @param position the position + * @param item the item to drop + * @see #dropItem(Vector3, BaseItemStack, int) shortcut method to specify the number of stacks + */ + void dropItem(Vector3 position, BaseItemStack item); + + /** + * Simulate a block being mined at the given position. + * + * @param position the position + */ + void simulateBlockMine(BlockVector3 position); + + /** + * Gets whether the given {@link BlockState} can be placed here. + * + * @param position The position + * @param blockState The blockstate + * @return If it can be placed + */ + default boolean canPlaceAt(BlockVector3 position, BlockState blockState) { + return true; + } + + /** + * Regenerate an area. + * + * @param region the region + * @param editSession the {@link EditSession} + * @return true if re-generation was successful + */ + default boolean regenerate(Region region, EditSession editSession) { + return regenerate(region, editSession, RegenOptions.builder().build()); + } + + /** + * Regenerate an area. + * + * @param region the region + * @param extent the {@link Extent} + * @return true if re-generation was successful + */ + default boolean regenerate(Region region, Extent extent) { + return regenerate(region, extent, RegenOptions.builder().build()); + } + + /** + * Regenerate an area. + * + * @param region the region + * @param extent the {@link Extent} + * @param options the regeneration options + * @return true if regeneration was successful + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "regenerate", + delegateParams = { Region.class, EditSession.class } + ) + default boolean regenerate(Region region, Extent extent, RegenOptions options) { + DeprecationUtil.checkDelegatingOverride(getClass()); + if (extent instanceof EditSession) { + return regenerate(region, (EditSession) extent); + } + throw new UnsupportedOperationException("This World class (" + + getClass().getName() + + ") does not implement the general Extent variant of this method"); + } + + /** + * Generate a tree at the given position. + * + * @param type the tree type + * @param editSession the {@link EditSession} + * @param position the position + * @return true if generation was successful + * @throws MaxChangedBlocksException thrown if too many blocks were changed + */ + boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException; + + /** + * Load the chunk at the given position if it isn't loaded. + * + * @param position the position + */ + void checkLoadedChunk(BlockVector3 position); + + /** + * Fix the given chunks after fast mode was used. + * + *

Fast mode makes calls to {@link #setBlock(BlockVector3, BlockStateHolder, boolean)} + * with {@code false} for the {@code notifyAndLight} parameter, which + * may causes lighting errors to accumulate. Use of this method, if + * it is implemented by the underlying world, corrects those lighting + * errors and may trigger block change notifications.

+ * + * @param chunks a list of chunk coordinates to fix + */ + void fixAfterFastMode(Iterable chunks); + + /** + * Relight the given chunks if possible. + * + * @param chunks a list of chunk coordinates to fix + */ + void fixLighting(Iterable chunks); + + /** + * Play the given effect. + * + * @param position the position + * @param type the effect type + * @param data the effect data + * @return true if the effect was played + */ + boolean playEffect(Vector3 position, int type, int data); + + /** + * Queue a block break effect. + * + * @param server the server + * @param position the position + * @param blockType the block type + * @param priority the priority + * @return true if the effect was played + */ + boolean queueBlockBreakEffect(Platform server, BlockVector3 position, BlockType blockType, double priority); + + /** + * Gets the weather type of the world. + * + * @return The weather + */ + WeatherType getWeather(); + + /** + * Gets the remaining weather duration. + * + * @return The weather duration + */ + long getRemainingWeatherDuration(); + + /** + * Sets the weather type of the world. + * + * @param weatherType The weather type + */ + void setWeather(WeatherType weatherType); + + /** + * Sets the weather type of the world. + * + * @param weatherType The weather type + * @param duration The duration of the weather + */ + void setWeather(WeatherType weatherType, long duration); + + /** + * Gets the spawn position of this world. + * + * @return The spawn position + */ + BlockVector3 getSpawnPosition(); + + @Override + boolean equals(Object other); + + @Override + int hashCode(); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/WorldUnloadedException.java b/src/main/java/com/sk89q/worldedit/world/WorldUnloadedException.java new file mode 100644 index 0000000..bbabeda --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/WorldUnloadedException.java @@ -0,0 +1,36 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world; + +import com.sk89q.worldedit.WorldEditException; +import net.kyori.text.TranslatableComponent; + +/** + * Thrown if the world has been unloaded. + */ +public class WorldUnloadedException extends WorldEditException { + + /** + * Create a new instance. + */ + public WorldUnloadedException() { + super(TranslatableComponent.of("worldedit.error.world-unloaded")); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/biome/BiomeData.java b/src/main/java/com/sk89q/worldedit/world/biome/BiomeData.java new file mode 100644 index 0000000..7230772 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/biome/BiomeData.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.biome; + +import com.sk89q.worldedit.world.registry.BiomeRegistry; + +/** + * Provides information about a biome. + * + * @deprecated This no longer returns useful information. + */ +@Deprecated +public interface BiomeData { + + /** + * Get the name of the biome, which does not have to follow any + * particular convention. + * + * @return the biome's name + * @deprecated This method does not work on the server. + * Use {@link BiomeRegistry#getRichName(BiomeType)}. + */ + @Deprecated + String getName(); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/biome/BiomeName.java b/src/main/java/com/sk89q/worldedit/world/biome/BiomeName.java new file mode 100644 index 0000000..6c7e338 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/biome/BiomeName.java @@ -0,0 +1,60 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.biome; + +import com.google.common.base.Function; +import com.sk89q.worldedit.world.registry.BiomeRegistry; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Returns the name of a biome using a given {@code BiomeRegistry}. + * + * @deprecated for removal, appears to be unused + */ +@Deprecated +class BiomeName implements Function { + + private final BiomeRegistry registry; + + /** + * Create a new instance. + * + * @param registry the biome registry + */ + BiomeName(BiomeRegistry registry) { + checkNotNull(registry); + this.registry = registry; + } + + @Nullable + @Override + public String apply(BiomeType input) { + BiomeData data = registry.getData(input); + if (data != null) { + return data.getName(); + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java b/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java new file mode 100644 index 0000000..c37a4a4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.biome; + +import com.sk89q.worldedit.function.pattern.BiomePattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; + +/** + * All the types of biomes in the game. + */ +public class BiomeType implements Keyed, BiomePattern { + + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("biome type", true); + + private final String id; + + public BiomeType(String id) { + this.id = id; + } + + /** + * Gets the ID of this biome. + * + * @return The id + */ + @Override + public String getId() { + return this.id; + } + + @Override + public String toString() { + return getId(); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof BiomeType && this.id.equals(((BiomeType) obj).id); + } + + @Override + public BiomeType applyBiome(BlockVector3 position) { + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java b/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java new file mode 100644 index 0000000..e54423b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java @@ -0,0 +1,144 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.biome; + +import javax.annotation.Nullable; + +/** + * Stores a list of common {@link BiomeType BiomeTypes}. + * + * @see BiomeType + */ +@SuppressWarnings("unused") +public final class BiomeTypes { + @Nullable public static final BiomeType BADLANDS = get("minecraft:badlands"); + @Deprecated @Nullable public static final BiomeType BADLANDS_PLATEAU = get("minecraft:badlands_plateau"); + @Nullable public static final BiomeType BAMBOO_JUNGLE = get("minecraft:bamboo_jungle"); + @Deprecated @Nullable public static final BiomeType BAMBOO_JUNGLE_HILLS = get("minecraft:bamboo_jungle_hills"); + @Nullable public static final BiomeType BASALT_DELTAS = get("minecraft:basalt_deltas"); + @Nullable public static final BiomeType BEACH = get("minecraft:beach"); + @Nullable public static final BiomeType BIRCH_FOREST = get("minecraft:birch_forest"); + @Deprecated @Nullable public static final BiomeType BIRCH_FOREST_HILLS = get("minecraft:birch_forest_hills"); + @Nullable public static final BiomeType CHERRY_GROVE = get("minecraft:cherry_grove"); + @Nullable public static final BiomeType COLD_OCEAN = get("minecraft:cold_ocean"); + @Nullable public static final BiomeType CRIMSON_FOREST = get("minecraft:crimson_forest"); + @Nullable public static final BiomeType DARK_FOREST = get("minecraft:dark_forest"); + @Deprecated @Nullable public static final BiomeType DARK_FOREST_HILLS = get("minecraft:dark_forest_hills"); + @Nullable public static final BiomeType DEEP_COLD_OCEAN = get("minecraft:deep_cold_ocean"); + @Nullable public static final BiomeType DEEP_DARK = get("minecraft:deep_dark"); + @Nullable public static final BiomeType DEEP_FROZEN_OCEAN = get("minecraft:deep_frozen_ocean"); + @Nullable public static final BiomeType DEEP_LUKEWARM_OCEAN = get("minecraft:deep_lukewarm_ocean"); + @Nullable public static final BiomeType DEEP_OCEAN = get("minecraft:deep_ocean"); + @Deprecated @Nullable public static final BiomeType DEEP_WARM_OCEAN = get("minecraft:deep_warm_ocean"); + @Nullable public static final BiomeType DESERT = get("minecraft:desert"); + @Deprecated @Nullable public static final BiomeType DESERT_HILLS = get("minecraft:desert_hills"); + @Deprecated @Nullable public static final BiomeType DESERT_LAKES = get("minecraft:desert_lakes"); + @Nullable public static final BiomeType DRIPSTONE_CAVES = get("minecraft:dripstone_caves"); + @Nullable public static final BiomeType END_BARRENS = get("minecraft:end_barrens"); + @Nullable public static final BiomeType END_HIGHLANDS = get("minecraft:end_highlands"); + @Nullable public static final BiomeType END_MIDLANDS = get("minecraft:end_midlands"); + @Nullable public static final BiomeType ERODED_BADLANDS = get("minecraft:eroded_badlands"); + @Nullable public static final BiomeType FLOWER_FOREST = get("minecraft:flower_forest"); + @Nullable public static final BiomeType FOREST = get("minecraft:forest"); + @Nullable public static final BiomeType FROZEN_OCEAN = get("minecraft:frozen_ocean"); + @Nullable public static final BiomeType FROZEN_PEAKS = get("minecraft:frozen_peaks"); + @Nullable public static final BiomeType FROZEN_RIVER = get("minecraft:frozen_river"); + @Deprecated @Nullable public static final BiomeType GIANT_SPRUCE_TAIGA = get("minecraft:giant_spruce_taiga"); + @Deprecated @Nullable public static final BiomeType GIANT_SPRUCE_TAIGA_HILLS = get("minecraft:giant_spruce_taiga_hills"); + @Deprecated @Nullable public static final BiomeType GIANT_TREE_TAIGA = get("minecraft:giant_tree_taiga"); + @Deprecated @Nullable public static final BiomeType GIANT_TREE_TAIGA_HILLS = get("minecraft:giant_tree_taiga_hills"); + @Deprecated @Nullable public static final BiomeType GRAVELLY_MOUNTAINS = get("minecraft:gravelly_mountains"); + @Nullable public static final BiomeType GROVE = get("minecraft:grove"); + @Nullable public static final BiomeType ICE_SPIKES = get("minecraft:ice_spikes"); + @Nullable public static final BiomeType JAGGED_PEAKS = get("minecraft:jagged_peaks"); + @Nullable public static final BiomeType JUNGLE = get("minecraft:jungle"); + @Deprecated @Nullable public static final BiomeType JUNGLE_EDGE = get("minecraft:jungle_edge"); + @Deprecated @Nullable public static final BiomeType JUNGLE_HILLS = get("minecraft:jungle_hills"); + @Nullable public static final BiomeType LUKEWARM_OCEAN = get("minecraft:lukewarm_ocean"); + @Nullable public static final BiomeType LUSH_CAVES = get("minecraft:lush_caves"); + @Nullable public static final BiomeType MANGROVE_SWAMP = get("minecraft:mangrove_swamp"); + @Nullable public static final BiomeType MEADOW = get("minecraft:meadow"); + @Deprecated @Nullable public static final BiomeType MODIFIED_BADLANDS_PLATEAU = get("minecraft:modified_badlands_plateau"); + @Deprecated @Nullable public static final BiomeType MODIFIED_GRAVELLY_HILLS = get("minecraft:modified_gravelly_hills"); + @Deprecated @Nullable public static final BiomeType MODIFIED_GRAVELLY_MOUNTAINS = get("minecraft:modified_gravelly_mountains"); + @Deprecated @Nullable public static final BiomeType MODIFIED_JUNGLE = get("minecraft:modified_jungle"); + @Deprecated @Nullable public static final BiomeType MODIFIED_JUNGLE_EDGE = get("minecraft:modified_jungle_edge"); + @Deprecated @Nullable public static final BiomeType MODIFIED_WOODED_BADLANDS_PLATEAU = get("minecraft:modified_wooded_badlands_plateau"); + @Deprecated @Nullable public static final BiomeType MOUNTAIN_EDGE = get("minecraft:mountain_edge"); + @Deprecated @Nullable public static final BiomeType MOUNTAINS = get("minecraft:mountains"); + @Deprecated @Nullable public static final BiomeType MUSHROOM_FIELD_SHORE = get("minecraft:mushroom_field_shore"); + @Nullable public static final BiomeType MUSHROOM_FIELDS = get("minecraft:mushroom_fields"); + @Deprecated @Nullable public static final BiomeType NETHER = get("minecraft:nether"); + @Nullable public static final BiomeType NETHER_WASTES = get("minecraft:nether_wastes"); + @Nullable public static final BiomeType OCEAN = get("minecraft:ocean"); + @Nullable public static final BiomeType OLD_GROWTH_BIRCH_FOREST = get("minecraft:old_growth_birch_forest"); + @Nullable public static final BiomeType OLD_GROWTH_PINE_TAIGA = get("minecraft:old_growth_pine_taiga"); + @Nullable public static final BiomeType OLD_GROWTH_SPRUCE_TAIGA = get("minecraft:old_growth_spruce_taiga"); + @Nullable public static final BiomeType PLAINS = get("minecraft:plains"); + @Nullable public static final BiomeType RIVER = get("minecraft:river"); + @Nullable public static final BiomeType SAVANNA = get("minecraft:savanna"); + @Nullable public static final BiomeType SAVANNA_PLATEAU = get("minecraft:savanna_plateau"); + @Deprecated @Nullable public static final BiomeType SHATTERED_SAVANNA = get("minecraft:shattered_savanna"); + @Deprecated @Nullable public static final BiomeType SHATTERED_SAVANNA_PLATEAU = get("minecraft:shattered_savanna_plateau"); + @Nullable public static final BiomeType SMALL_END_ISLANDS = get("minecraft:small_end_islands"); + @Nullable public static final BiomeType SNOWY_BEACH = get("minecraft:snowy_beach"); + @Deprecated @Nullable public static final BiomeType SNOWY_MOUNTAINS = get("minecraft:snowy_mountains"); + @Nullable public static final BiomeType SNOWY_PLAINS = get("minecraft:snowy_plains"); + @Nullable public static final BiomeType SNOWY_SLOPES = get("minecraft:snowy_slopes"); + @Nullable public static final BiomeType SNOWY_TAIGA = get("minecraft:snowy_taiga"); + @Deprecated @Nullable public static final BiomeType SNOWY_TAIGA_HILLS = get("minecraft:snowy_taiga_hills"); + @Deprecated @Nullable public static final BiomeType SNOWY_TAIGA_MOUNTAINS = get("minecraft:snowy_taiga_mountains"); + @Deprecated @Nullable public static final BiomeType SNOWY_TUNDRA = get("minecraft:snowy_tundra"); + @Nullable public static final BiomeType SOUL_SAND_VALLEY = get("minecraft:soul_sand_valley"); + @Nullable public static final BiomeType SPARSE_JUNGLE = get("minecraft:sparse_jungle"); + @Deprecated @Nullable public static final BiomeType STONE_SHORE = get("minecraft:stone_shore"); + @Nullable public static final BiomeType STONY_PEAKS = get("minecraft:stony_peaks"); + @Nullable public static final BiomeType STONY_SHORE = get("minecraft:stony_shore"); + @Nullable public static final BiomeType SUNFLOWER_PLAINS = get("minecraft:sunflower_plains"); + @Nullable public static final BiomeType SWAMP = get("minecraft:swamp"); + @Deprecated @Nullable public static final BiomeType SWAMP_HILLS = get("minecraft:swamp_hills"); + @Nullable public static final BiomeType TAIGA = get("minecraft:taiga"); + @Deprecated @Nullable public static final BiomeType TAIGA_HILLS = get("minecraft:taiga_hills"); + @Deprecated @Nullable public static final BiomeType TAIGA_MOUNTAINS = get("minecraft:taiga_mountains"); + @Deprecated @Nullable public static final BiomeType TALL_BIRCH_FOREST = get("minecraft:tall_birch_forest"); + @Deprecated @Nullable public static final BiomeType TALL_BIRCH_HILLS = get("minecraft:tall_birch_hills"); + @Nullable public static final BiomeType THE_END = get("minecraft:the_end"); + @Nullable public static final BiomeType THE_VOID = get("minecraft:the_void"); + @Nullable public static final BiomeType WARM_OCEAN = get("minecraft:warm_ocean"); + @Nullable public static final BiomeType WARPED_FOREST = get("minecraft:warped_forest"); + @Nullable public static final BiomeType WINDSWEPT_FOREST = get("minecraft:windswept_forest"); + @Nullable public static final BiomeType WINDSWEPT_GRAVELLY_HILLS = get("minecraft:windswept_gravelly_hills"); + @Nullable public static final BiomeType WINDSWEPT_HILLS = get("minecraft:windswept_hills"); + @Nullable public static final BiomeType WINDSWEPT_SAVANNA = get("minecraft:windswept_savanna"); + @Nullable public static final BiomeType WOODED_BADLANDS = get("minecraft:wooded_badlands"); + @Deprecated @Nullable public static final BiomeType WOODED_BADLANDS_PLATEAU = get("minecraft:wooded_badlands_plateau"); + @Deprecated @Nullable public static final BiomeType WOODED_HILLS = get("minecraft:wooded_hills"); + @Deprecated @Nullable public static final BiomeType WOODED_MOUNTAINS = get("minecraft:wooded_mountains"); + + private BiomeTypes() { + } + + /** + * Gets the {@link BiomeType} associated with the given id. + */ + public static @Nullable BiomeType get(String id) { + return BiomeType.REGISTRY.get(id); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/biome/Biomes.java b/src/main/java/com/sk89q/worldedit/world/biome/Biomes.java new file mode 100644 index 0000000..5c20fea --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/biome/Biomes.java @@ -0,0 +1,75 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.biome; + +import com.google.common.base.Functions; +import com.sk89q.worldedit.util.WeightedChoice; +import com.sk89q.worldedit.util.WeightedChoice.Choice; +import com.sk89q.worldedit.util.function.LevenshteinDistance; +import com.sk89q.worldedit.world.registry.BiomeRegistry; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Optional; +import java.util.function.Function; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Utility methods related to biomes. + * + * @deprecated Only method is being deprecated for removal. + */ +@Deprecated +public final class Biomes { + + private Biomes() { + } + + /** + * Find a biome that matches the given input name. + * + * @param biomes a list of biomes + * @param name the name to test + * @param registry a biome registry + * @return a biome or null + * @deprecated This uses the outdated name system. Find names by comparing with their ID instead. + */ + @Deprecated + @Nullable + public static BiomeType findBiomeByName(Collection biomes, String name, BiomeRegistry registry) { + checkNotNull(biomes); + checkNotNull(name); + checkNotNull(registry); + + Function compare = new LevenshteinDistance(name, false, LevenshteinDistance.STANDARD_CHARS); + WeightedChoice chooser = new WeightedChoice<>(Functions.compose(compare::apply, new BiomeName(registry)), 0); + for (BiomeType biome : biomes) { + chooser.consider(biome); + } + Optional> choice = chooser.getChoice(); + if (choice.isPresent() && choice.get().getScore() <= 1) { + return choice.get().getValue(); + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java new file mode 100644 index 0000000..a7d50f6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -0,0 +1,196 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.block; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.blocks.TileEntityBlock; +import com.sk89q.worldedit.registry.state.Property; + +import java.util.Map; +import java.util.Objects; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a "snapshot" of a block with NBT Data. + * + *

An instance of this block contains all the information needed to + * accurately reproduce the block, provided that the instance was + * made correctly. In some implementations, it may not be possible to get a + * snapshot of blocks correctly, so, for example, the NBT data for a block + * may be missing.

+ */ +public class BaseBlock implements BlockStateHolder, TileEntityBlock { + + private final BlockState blockState; + @Nullable + private final CompoundTag nbtData; + + /** + * Construct a block with a state. + * + * @param blockState The blockstate + */ + protected BaseBlock(BlockState blockState) { + this.blockState = blockState; + this.nbtData = null; + } + + /** + * Construct a block with the given ID, data value and NBT data structure. + * + * @param state The block state + * @param nbtData NBT data, which must be provided + */ + protected BaseBlock(BlockState state, CompoundTag nbtData) { + checkNotNull(nbtData); + this.blockState = state; + this.nbtData = nbtData; + } + + /** + * Gets a map of state to state values. + * + * @return The state map + */ + @Override + public Map, Object> getStates() { + return this.blockState.getStates(); + } + + @Override + public BlockType getBlockType() { + return this.blockState.getBlockType(); + } + + @Override + public BaseBlock with(Property property, V value) { + return this.blockState.with(property, value).toBaseBlock(getNbtData()); + } + + /** + * Gets the State for this Block. + * + * @param property The state to get the value for + * @return The state value + */ + @Override + public V getState(Property property) { + return this.blockState.getState(property); + } + + @Override + public boolean hasNbtData() { + return getNbtData() != null; + } + + @Override + public String getNbtId() { + CompoundTag nbtData = getNbtData(); + if (nbtData == null) { + return ""; + } + Tag idTag = nbtData.getValue().get("id"); + if (idTag instanceof StringTag) { + return ((StringTag) idTag).getValue(); + } else { + return ""; + } + } + + @Nullable + @Override + public CompoundTag getNbtData() { + return this.nbtData; + } + + @Override + public void setNbtData(@Nullable CompoundTag nbtData) { + throw new UnsupportedOperationException("This class is immutable."); + } + + /** + * Checks whether the type ID and data value are equal. + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof BaseBlock)) { + if (!hasNbtData() && o instanceof BlockStateHolder) { + return Objects.equals(toImmutableState(), ((BlockStateHolder) o).toImmutableState()); + } + return false; + } + + final BaseBlock otherBlock = (BaseBlock) o; + + return this.blockState.equalsFuzzy(otherBlock.blockState) && Objects.equals(getNbtData(), otherBlock.getNbtData()); + } + + /** + * Checks if the type is the same, and if the matched states are the same. + * + * @param o other block + * @return true if equal + */ + @Override + public boolean equalsFuzzy(BlockStateHolder o) { + return this.blockState.equalsFuzzy(o); + } + + @Override + public BlockState toImmutableState() { + return this.blockState; + } + + @Override + public BaseBlock toBaseBlock() { + return this; + } + + @Override + public BaseBlock toBaseBlock(CompoundTag compoundTag) { + if (compoundTag == null) { + return this.blockState.toBaseBlock(); + } else if (compoundTag == this.nbtData) { + return this; + } else { + return new BaseBlock(this.blockState, compoundTag); + } + } + + @Override + public int hashCode() { + int ret = toImmutableState().hashCode() << 3; + if (hasNbtData()) { + ret += getNbtData().hashCode(); + } + return ret; + } + + @Override + public String toString() { + // TODO use a json serializer for the NBT data + return blockState.getAsString() + (hasNbtData() ? "{hasNbt}" : ""); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java b/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java new file mode 100644 index 0000000..d5f9ce5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java @@ -0,0 +1,217 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.block; + +/** + * Stores a list of common {@link BlockCategory BlockCategories}. + * + * @see BlockCategory + */ +@SuppressWarnings("unused") +public final class BlockCategories { + public static final BlockCategory ACACIA_LOGS = get("minecraft:acacia_logs"); + public static final BlockCategory ALL_HANGING_SIGNS = get("minecraft:all_hanging_signs"); + public static final BlockCategory ALL_SIGNS = get("minecraft:all_signs"); + public static final BlockCategory ANCIENT_CITY_REPLACEABLE = get("minecraft:ancient_city_replaceable"); + public static final BlockCategory ANIMALS_SPAWNABLE_ON = get("minecraft:animals_spawnable_on"); + public static final BlockCategory ANVIL = get("minecraft:anvil"); + public static final BlockCategory AXOLOTLS_SPAWNABLE_ON = get("minecraft:axolotls_spawnable_on"); + public static final BlockCategory AZALEA_GROWS_ON = get("minecraft:azalea_grows_on"); + public static final BlockCategory AZALEA_ROOT_REPLACEABLE = get("minecraft:azalea_root_replaceable"); + public static final BlockCategory BAMBOO_BLOCKS = get("minecraft:bamboo_blocks"); + public static final BlockCategory BAMBOO_PLANTABLE_ON = get("minecraft:bamboo_plantable_on"); + public static final BlockCategory BANNERS = get("minecraft:banners"); + public static final BlockCategory BASE_STONE_NETHER = get("minecraft:base_stone_nether"); + public static final BlockCategory BASE_STONE_OVERWORLD = get("minecraft:base_stone_overworld"); + public static final BlockCategory BEACON_BASE_BLOCKS = get("minecraft:beacon_base_blocks"); + public static final BlockCategory BEDS = get("minecraft:beds"); + public static final BlockCategory BEE_GROWABLES = get("minecraft:bee_growables"); + public static final BlockCategory BEEHIVES = get("minecraft:beehives"); + public static final BlockCategory BIG_DRIPLEAF_PLACEABLE = get("minecraft:big_dripleaf_placeable"); + public static final BlockCategory BIRCH_LOGS = get("minecraft:birch_logs"); + public static final BlockCategory BUTTONS = get("minecraft:buttons"); + public static final BlockCategory CAMPFIRES = get("minecraft:campfires"); + public static final BlockCategory CANDLE_CAKES = get("minecraft:candle_cakes"); + public static final BlockCategory CANDLES = get("minecraft:candles"); + @Deprecated public static final BlockCategory CARPETS = get("minecraft:carpets"); + public static final BlockCategory CAULDRONS = get("minecraft:cauldrons"); + public static final BlockCategory CAVE_VINES = get("minecraft:cave_vines"); + public static final BlockCategory CEILING_HANGING_SIGNS = get("minecraft:ceiling_hanging_signs"); + public static final BlockCategory CHERRY_LOGS = get("minecraft:cherry_logs"); + public static final BlockCategory CLIMBABLE = get("minecraft:climbable"); + public static final BlockCategory COAL_ORES = get("minecraft:coal_ores"); + public static final BlockCategory COMBINATION_STEP_SOUND_BLOCKS = get("minecraft:combination_step_sound_blocks"); + public static final BlockCategory COMPLETES_FIND_TREE_TUTORIAL = get("minecraft:completes_find_tree_tutorial"); + public static final BlockCategory CONVERTABLE_TO_MUD = get("minecraft:convertable_to_mud"); + public static final BlockCategory COPPER_ORES = get("minecraft:copper_ores"); + public static final BlockCategory CORAL_BLOCKS = get("minecraft:coral_blocks"); + public static final BlockCategory CORAL_PLANTS = get("minecraft:coral_plants"); + public static final BlockCategory CORALS = get("minecraft:corals"); + public static final BlockCategory CRIMSON_STEMS = get("minecraft:crimson_stems"); + public static final BlockCategory CROPS = get("minecraft:crops"); + public static final BlockCategory CRYSTAL_SOUND_BLOCKS = get("minecraft:crystal_sound_blocks"); + public static final BlockCategory DAMPENS_VIBRATIONS = get("minecraft:dampens_vibrations"); + public static final BlockCategory DARK_OAK_LOGS = get("minecraft:dark_oak_logs"); + public static final BlockCategory DEAD_BUSH_MAY_PLACE_ON = get("minecraft:dead_bush_may_place_on"); + public static final BlockCategory DEEPSLATE_ORE_REPLACEABLES = get("minecraft:deepslate_ore_replaceables"); + public static final BlockCategory DIAMOND_ORES = get("minecraft:diamond_ores"); + public static final BlockCategory DIRT = get("minecraft:dirt"); + @Deprecated public static final BlockCategory DIRT_LIKE = get("minecraft:dirt_like"); + public static final BlockCategory DOORS = get("minecraft:doors"); + public static final BlockCategory DRAGON_IMMUNE = get("minecraft:dragon_immune"); + public static final BlockCategory DRAGON_TRANSPARENT = get("minecraft:dragon_transparent"); + public static final BlockCategory DRIPSTONE_REPLACEABLE_BLOCKS = get("minecraft:dripstone_replaceable_blocks"); + public static final BlockCategory EMERALD_ORES = get("minecraft:emerald_ores"); + public static final BlockCategory ENCHANTMENT_POWER_PROVIDER = get("minecraft:enchantment_power_provider"); + public static final BlockCategory ENCHANTMENT_POWER_TRANSMITTER = get("minecraft:enchantment_power_transmitter"); + public static final BlockCategory ENDERMAN_HOLDABLE = get("minecraft:enderman_holdable"); + public static final BlockCategory FALL_DAMAGE_RESETTING = get("minecraft:fall_damage_resetting"); + public static final BlockCategory FEATURES_CANNOT_REPLACE = get("minecraft:features_cannot_replace"); + public static final BlockCategory FENCE_GATES = get("minecraft:fence_gates"); + public static final BlockCategory FENCES = get("minecraft:fences"); + public static final BlockCategory FIRE = get("minecraft:fire"); + public static final BlockCategory FLOWER_POTS = get("minecraft:flower_pots"); + public static final BlockCategory FLOWERS = get("minecraft:flowers"); + public static final BlockCategory FOXES_SPAWNABLE_ON = get("minecraft:foxes_spawnable_on"); + public static final BlockCategory FROG_PREFER_JUMP_TO = get("minecraft:frog_prefer_jump_to"); + public static final BlockCategory FROGS_SPAWNABLE_ON = get("minecraft:frogs_spawnable_on"); + public static final BlockCategory GEODE_INVALID_BLOCKS = get("minecraft:geode_invalid_blocks"); + public static final BlockCategory GOATS_SPAWNABLE_ON = get("minecraft:goats_spawnable_on"); + public static final BlockCategory GOLD_ORES = get("minecraft:gold_ores"); + public static final BlockCategory GUARDED_BY_PIGLINS = get("minecraft:guarded_by_piglins"); + public static final BlockCategory HOGLIN_REPELLENTS = get("minecraft:hoglin_repellents"); + public static final BlockCategory ICE = get("minecraft:ice"); + public static final BlockCategory IMPERMEABLE = get("minecraft:impermeable"); + public static final BlockCategory INFINIBURN_END = get("minecraft:infiniburn_end"); + public static final BlockCategory INFINIBURN_NETHER = get("minecraft:infiniburn_nether"); + public static final BlockCategory INFINIBURN_OVERWORLD = get("minecraft:infiniburn_overworld"); + public static final BlockCategory INSIDE_STEP_SOUND_BLOCKS = get("minecraft:inside_step_sound_blocks"); + public static final BlockCategory INVALID_SPAWN_INSIDE = get("minecraft:invalid_spawn_inside"); + public static final BlockCategory IRON_ORES = get("minecraft:iron_ores"); + public static final BlockCategory JUNGLE_LOGS = get("minecraft:jungle_logs"); + public static final BlockCategory LAPIS_ORES = get("minecraft:lapis_ores"); + public static final BlockCategory LAVA_POOL_STONE_CANNOT_REPLACE = get("minecraft:lava_pool_stone_cannot_replace"); + @Deprecated public static final BlockCategory LAVA_POOL_STONE_REPLACEABLES = get("minecraft:lava_pool_stone_replaceables"); + public static final BlockCategory LEAVES = get("minecraft:leaves"); + public static final BlockCategory LOGS = get("minecraft:logs"); + public static final BlockCategory LOGS_THAT_BURN = get("minecraft:logs_that_burn"); + public static final BlockCategory LUSH_GROUND_REPLACEABLE = get("minecraft:lush_ground_replaceable"); + public static final BlockCategory MAINTAINS_FARMLAND = get("minecraft:maintains_farmland"); + public static final BlockCategory MANGROVE_LOGS = get("minecraft:mangrove_logs"); + public static final BlockCategory MANGROVE_LOGS_CAN_GROW_THROUGH = get("minecraft:mangrove_logs_can_grow_through"); + public static final BlockCategory MANGROVE_ROOTS_CAN_GROW_THROUGH = get("minecraft:mangrove_roots_can_grow_through"); + public static final BlockCategory MINEABLE_AXE = get("minecraft:mineable/axe"); + public static final BlockCategory MINEABLE_HOE = get("minecraft:mineable/hoe"); + public static final BlockCategory MINEABLE_PICKAXE = get("minecraft:mineable/pickaxe"); + public static final BlockCategory MINEABLE_SHOVEL = get("minecraft:mineable/shovel"); + public static final BlockCategory MOOSHROOMS_SPAWNABLE_ON = get("minecraft:mooshrooms_spawnable_on"); + public static final BlockCategory MOSS_REPLACEABLE = get("minecraft:moss_replaceable"); + public static final BlockCategory MUSHROOM_GROW_BLOCK = get("minecraft:mushroom_grow_block"); + public static final BlockCategory NEEDS_DIAMOND_TOOL = get("minecraft:needs_diamond_tool"); + public static final BlockCategory NEEDS_IRON_TOOL = get("minecraft:needs_iron_tool"); + public static final BlockCategory NEEDS_STONE_TOOL = get("minecraft:needs_stone_tool"); + public static final BlockCategory NETHER_CARVER_REPLACEABLES = get("minecraft:nether_carver_replaceables"); + public static final BlockCategory NYLIUM = get("minecraft:nylium"); + public static final BlockCategory OAK_LOGS = get("minecraft:oak_logs"); + public static final BlockCategory OCCLUDES_VIBRATION_SIGNALS = get("minecraft:occludes_vibration_signals"); + public static final BlockCategory OVERWORLD_CARVER_REPLACEABLES = get("minecraft:overworld_carver_replaceables"); + public static final BlockCategory OVERWORLD_NATURAL_LOGS = get("minecraft:overworld_natural_logs"); + public static final BlockCategory PARROTS_SPAWNABLE_ON = get("minecraft:parrots_spawnable_on"); + public static final BlockCategory PIGLIN_REPELLENTS = get("minecraft:piglin_repellents"); + public static final BlockCategory PLANKS = get("minecraft:planks"); + public static final BlockCategory POLAR_BEARS_SPAWNABLE_ON_ALTERNATE = get("minecraft:polar_bears_spawnable_on_alternate"); + public static final BlockCategory PORTALS = get("minecraft:portals"); + public static final BlockCategory PRESSURE_PLATES = get("minecraft:pressure_plates"); + public static final BlockCategory PREVENT_MOB_SPAWNING_INSIDE = get("minecraft:prevent_mob_spawning_inside"); + public static final BlockCategory RABBITS_SPAWNABLE_ON = get("minecraft:rabbits_spawnable_on"); + public static final BlockCategory RAILS = get("minecraft:rails"); + public static final BlockCategory REDSTONE_ORES = get("minecraft:redstone_ores"); + public static final BlockCategory REPLACEABLE = get("minecraft:replaceable"); + public static final BlockCategory REPLACEABLE_BY_TREES = get("minecraft:replaceable_by_trees"); + @Deprecated public static final BlockCategory REPLACEABLE_PLANTS = get("minecraft:replaceable_plants"); + public static final BlockCategory SAND = get("minecraft:sand"); + public static final BlockCategory SAPLINGS = get("minecraft:saplings"); + public static final BlockCategory SCULK_REPLACEABLE = get("minecraft:sculk_replaceable"); + public static final BlockCategory SCULK_REPLACEABLE_WORLD_GEN = get("minecraft:sculk_replaceable_world_gen"); + public static final BlockCategory SHULKER_BOXES = get("minecraft:shulker_boxes"); + public static final BlockCategory SIGNS = get("minecraft:signs"); + public static final BlockCategory SLABS = get("minecraft:slabs"); + public static final BlockCategory SMALL_DRIPLEAF_PLACEABLE = get("minecraft:small_dripleaf_placeable"); + public static final BlockCategory SMALL_FLOWERS = get("minecraft:small_flowers"); + public static final BlockCategory SMELTS_TO_GLASS = get("minecraft:smelts_to_glass"); + public static final BlockCategory SNAPS_GOAT_HORN = get("minecraft:snaps_goat_horn"); + public static final BlockCategory SNIFFER_DIGGABLE_BLOCK = get("minecraft:sniffer_diggable_block"); + public static final BlockCategory SNIFFER_EGG_HATCH_BOOST = get("minecraft:sniffer_egg_hatch_boost"); + public static final BlockCategory SNOW = get("minecraft:snow"); + public static final BlockCategory SNOW_LAYER_CAN_SURVIVE_ON = get("minecraft:snow_layer_can_survive_on"); + public static final BlockCategory SNOW_LAYER_CANNOT_SURVIVE_ON = get("minecraft:snow_layer_cannot_survive_on"); + public static final BlockCategory SOUL_FIRE_BASE_BLOCKS = get("minecraft:soul_fire_base_blocks"); + public static final BlockCategory SOUL_SPEED_BLOCKS = get("minecraft:soul_speed_blocks"); + public static final BlockCategory SPRUCE_LOGS = get("minecraft:spruce_logs"); + public static final BlockCategory STAIRS = get("minecraft:stairs"); + public static final BlockCategory STANDING_SIGNS = get("minecraft:standing_signs"); + public static final BlockCategory STONE_BRICKS = get("minecraft:stone_bricks"); + public static final BlockCategory STONE_BUTTONS = get("minecraft:stone_buttons"); + public static final BlockCategory STONE_ORE_REPLACEABLES = get("minecraft:stone_ore_replaceables"); + public static final BlockCategory STONE_PRESSURE_PLATES = get("minecraft:stone_pressure_plates"); + public static final BlockCategory STRIDER_WARM_BLOCKS = get("minecraft:strider_warm_blocks"); + public static final BlockCategory SWORD_EFFICIENT = get("minecraft:sword_efficient"); + public static final BlockCategory TALL_FLOWERS = get("minecraft:tall_flowers"); + public static final BlockCategory TERRACOTTA = get("minecraft:terracotta"); + public static final BlockCategory TRAIL_RUINS_REPLACEABLE = get("minecraft:trail_ruins_replaceable"); + public static final BlockCategory TRAPDOORS = get("minecraft:trapdoors"); + public static final BlockCategory UNDERWATER_BONEMEALS = get("minecraft:underwater_bonemeals"); + public static final BlockCategory UNSTABLE_BOTTOM_CENTER = get("minecraft:unstable_bottom_center"); + public static final BlockCategory VALID_SPAWN = get("minecraft:valid_spawn"); + public static final BlockCategory VIBRATION_RESONATORS = get("minecraft:vibration_resonators"); + public static final BlockCategory WALL_CORALS = get("minecraft:wall_corals"); + public static final BlockCategory WALL_HANGING_SIGNS = get("minecraft:wall_hanging_signs"); + public static final BlockCategory WALL_POST_OVERRIDE = get("minecraft:wall_post_override"); + public static final BlockCategory WALL_SIGNS = get("minecraft:wall_signs"); + public static final BlockCategory WALLS = get("minecraft:walls"); + public static final BlockCategory WARPED_STEMS = get("minecraft:warped_stems"); + public static final BlockCategory WART_BLOCKS = get("minecraft:wart_blocks"); + public static final BlockCategory WITHER_IMMUNE = get("minecraft:wither_immune"); + public static final BlockCategory WITHER_SUMMON_BASE_BLOCKS = get("minecraft:wither_summon_base_blocks"); + public static final BlockCategory WOLVES_SPAWNABLE_ON = get("minecraft:wolves_spawnable_on"); + public static final BlockCategory WOODEN_BUTTONS = get("minecraft:wooden_buttons"); + public static final BlockCategory WOODEN_DOORS = get("minecraft:wooden_doors"); + public static final BlockCategory WOODEN_FENCES = get("minecraft:wooden_fences"); + public static final BlockCategory WOODEN_PRESSURE_PLATES = get("minecraft:wooden_pressure_plates"); + public static final BlockCategory WOODEN_SLABS = get("minecraft:wooden_slabs"); + public static final BlockCategory WOODEN_STAIRS = get("minecraft:wooden_stairs"); + public static final BlockCategory WOODEN_TRAPDOORS = get("minecraft:wooden_trapdoors"); + public static final BlockCategory WOOL = get("minecraft:wool"); + public static final BlockCategory WOOL_CARPETS = get("minecraft:wool_carpets"); + + private BlockCategories() { + } + + /** + * Gets the {@link BlockCategory} associated with the given id. + */ + public static BlockCategory get(String id) { + BlockCategory entry = BlockCategory.REGISTRY.get(id); + if (entry == null) { + return new BlockCategory(id); + } + return entry; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/block/BlockCategory.java b/src/main/java/com/sk89q/worldedit/world/block/BlockCategory.java new file mode 100644 index 0000000..a20e74d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/block/BlockCategory.java @@ -0,0 +1,59 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.block; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; + +import java.util.Set; + +/** + * A category of blocks. This is due to the splitting up of + * blocks such as wool into separate ids. + */ +public class BlockCategory extends Category implements Keyed { + + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("block tag", true); + + public BlockCategory(final String id) { + super(id); + } + + @Override + protected Set load() { + return WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries() + .getBlockCategoryRegistry().getAll(this); + } + + /** + * Checks whether the BlockStateHolder is contained within + * this category. + * + * @param blockStateHolder The blockstateholder + * @return If it's a part of this category + */ + public > boolean contains(B blockStateHolder) { + return this.getAll().contains(blockStateHolder.getBlockType()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/src/main/java/com/sk89q/worldedit/world/block/BlockState.java new file mode 100644 index 0000000..ec1d36c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -0,0 +1,273 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.block; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Table; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.registry.state.Property; + +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * An immutable class that represents the state a block can be in. + */ +@SuppressWarnings("unchecked") +public class BlockState implements BlockStateHolder { + + static { + BlockStateIdAccess.setBlockStateInternalId(new BlockStateIdAccess.BlockStateInternalId() { + @Override + public int getInternalId(BlockState blockState) { + return blockState.internalId; + } + + @Override + public void setInternalId(BlockState blockState, int internalId) { + blockState.internalId = internalId; + } + }); + } + + private final BlockType blockType; + private final Map, Object> values; + + private final BaseBlock emptyBaseBlock; + + // Neighbouring state table. + private Table, Object, BlockState> states; + + /** + * The internal ID of the block state. + */ + private volatile int internalId = BlockStateIdAccess.invalidId(); + + BlockState(BlockType blockType) { + this.blockType = blockType; + this.values = new LinkedHashMap<>(); + this.emptyBaseBlock = new BaseBlock(this); + } + + static Map, Object>, BlockState> generateStateMap(BlockType blockType) { + ImmutableMap.Builder, Object>, BlockState> stateMapBuilder = ImmutableMap.builder(); + List> properties = blockType.getProperties(); + + if (!properties.isEmpty()) { + List> separatedValues = Lists.newArrayList(); + for (Property prop : properties) { + List vals = Lists.newArrayList(); + vals.addAll(prop.getValues()); + separatedValues.add(vals); + } + List> valueLists = Lists.cartesianProduct(separatedValues); + for (List valueList : valueLists) { + Map, Object> valueMap = Maps.newTreeMap(Comparator.comparing(Property::getName)); + BlockState stateMaker = new BlockState(blockType); + for (int i = 0; i < valueList.size(); i++) { + Property property = properties.get(i); + Object value = valueList.get(i); + valueMap.put(property, value); + stateMaker.setState(property, value); + } + stateMapBuilder.put(ImmutableMap.copyOf(valueMap), stateMaker); + } + } + + ImmutableMap, Object>, BlockState> stateMap = stateMapBuilder.build(); + + if (stateMap.isEmpty()) { + // No properties. + stateMap = ImmutableMap.of(ImmutableMap.of(), new BlockState(blockType)); + } + + for (BlockState state : stateMap.values()) { + state.populate(stateMap); + } + + // Sometimes loading can take a while. This is the perfect spot to let MC know we're working. + Watchdog watchdog = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS) + .getWatchdog(); + if (watchdog != null) { + watchdog.tick(); + } + + return stateMap; + } + + private void populate(Map, Object>, BlockState> stateMap) { + final ImmutableTable.Builder, Object, BlockState> states = ImmutableTable.builder(); + + for (final Map.Entry, Object> entry : this.values.entrySet()) { + final Property property = (Property) entry.getKey(); + + for (Object value : property.getValues()) { + if (value != entry.getValue()) { + BlockState modifiedState = stateMap.get(this.withValue(property, value)); + if (modifiedState != null) { + states.put(property, value, modifiedState); + } else { + System.out.println(stateMap); + WorldEdit.logger.warn("Found a null state at " + this.withValue(property, value)); + } + } + } + } + + this.states = states.build(); + } + + private Map, Object> withValue(final Property property, final V value) { + final ImmutableMap.Builder, Object> values = ImmutableMap.builder(); + for (Map.Entry, Object> entry : this.values.entrySet()) { + if (entry.getKey().equals(property)) { + values.put(entry.getKey(), value); + } else { + values.put(entry); + } + } + return values.build(); + } + + @Override + public BlockType getBlockType() { + return this.blockType; + } + + @Override + public BlockState with(final Property property, final V value) { + BlockState result = states.get(property, value); + return result == null ? this : result; + } + + @Override + public V getState(final Property property) { + return (V) this.values.get(property); + } + + @Override + public Map, Object> getStates() { + return Collections.unmodifiableMap(this.values); + } + + @Override + public boolean equalsFuzzy(BlockStateHolder o) { + if (null == o) { + return false; + } + if (this == o) { + // Added a reference equality check for speediness + return true; + } + if (!getBlockType().equals(o.getBlockType())) { + return false; + } + + Set> differingProperties = new HashSet<>(); + for (Object state : o.getStates().keySet()) { + if (getState((Property) state) == null) { + differingProperties.add((Property) state); + } + } + for (Property property : getStates().keySet()) { + if (o.getState(property) == null) { + differingProperties.add(property); + } + } + + for (Property property : getStates().keySet()) { + if (differingProperties.contains(property)) { + continue; + } + if (!Objects.equals(getState(property), o.getState(property))) { + return false; + } + } + + return true; + } + + @Override + public BlockState toImmutableState() { + return this; + } + + @Override + public BaseBlock toBaseBlock() { + return this.emptyBaseBlock; + } + + @Override + public BaseBlock toBaseBlock(CompoundTag compoundTag) { + if (compoundTag == null) { + return toBaseBlock(); + } + return new BaseBlock(this, compoundTag); + } + + /** + * Internal method used for creating the initial BlockState. + * + * @param property The state + * @param value The value + * @return The blockstate, for chaining + */ + BlockState setState(final Property property, final Object value) { + this.values.put(property, value); + return this; + } + + @Override + public String toString() { + return getAsString(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof BlockState)) { + return false; + } + + return equalsFuzzy((BlockState) obj); + } + + private Integer hashCodeCache = null; + + @Override + public int hashCode() { + if (hashCodeCache == null) { + hashCodeCache = Objects.hash(blockType, values); + } + return hashCodeCache; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java b/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java new file mode 100644 index 0000000..93aaa55 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java @@ -0,0 +1,111 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.block; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; + +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; + +public interface BlockStateHolder> extends Pattern { + + /** + * Get the block type. + * + * @return The type + */ + BlockType getBlockType(); + + /** + * Returns a BlockState with the given state and value applied. + * + * @param property The state + * @param value The value + * @return The modified state, or same if could not be applied + */ + B with(final Property property, final V value); + + /** + * Gets the value for the given state. + * + * @param property The state + * @return The value + */ + V getState(Property property); + + /** + * Gets an immutable collection of the states. + * + * @return The states + */ + Map, Object> getStates(); + + /** + * Checks if the type is the same, and if the matched states are the same. + * + * @param o other block + * @return true if equal + */ + boolean equalsFuzzy(BlockStateHolder o); + + /** + * Returns an immutable {@link BlockState} from this BlockStateHolder. + * + * @return A BlockState + */ + BlockState toImmutableState(); + + /** + * Gets a {@link BaseBlock} from this BlockStateHolder. + * + * @return The BaseBlock + */ + BaseBlock toBaseBlock(); + + /** + * Gets a {@link BaseBlock} from this BlockStateHolder. + * + * @param compoundTag The NBT Data to apply + * @return The BaseBlock + */ + BaseBlock toBaseBlock(CompoundTag compoundTag); + + @Override + default BaseBlock applyBlock(BlockVector3 position) { + return toBaseBlock(); + } + + default String getAsString() { + if (getStates().isEmpty()) { + return this.getBlockType().getId(); + } else { + String properties = getStates().entrySet().stream() + .map(entry -> entry.getKey().getName() + + "=" + + entry.getValue().toString().toLowerCase(Locale.ROOT)) + .collect(Collectors.joining(",")); + return this.getBlockType().getId() + "[" + properties + "]"; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/block/BlockType.java b/src/main/java/com/sk89q/worldedit/world/block/BlockType.java new file mode 100644 index 0000000..447fb7b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/block/BlockType.java @@ -0,0 +1,264 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.block; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import net.kyori.text.Component; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import com.sk89q.worldedit.world.registry.LegacyMapper; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; + +public class BlockType implements Keyed { + + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("block type", true); + + private final String id; + private final Function values; + private final LazyReference defaultState + = LazyReference.from(this::computeDefaultState); + private final LazyReference emptyFuzzy + = LazyReference.from(() -> new FuzzyBlockState(this)); + private final LazyReference>> properties + = LazyReference.from(() -> ImmutableMap.copyOf(WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getProperties(this))); + private final LazyReference blockMaterial + = LazyReference.from(() -> WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getMaterial(this)); + private final LazyReference, Object>, BlockState>> blockStatesMap + = LazyReference.from(() -> BlockState.generateStateMap(this)); + + @Deprecated + private final LazyReference name = LazyReference.from(() -> WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getName(this)); + private final LazyReference legacyId = LazyReference.from(() -> computeLegacy(0)); + private final LazyReference legacyData = LazyReference.from(() -> computeLegacy(1)); + + public BlockType(String id) { + this(id, null); + } + + public BlockType(String id, Function values) { + // If it has no namespace, assume minecraft. + if (!id.contains(":")) { + id = "minecraft:" + id; + } + this.id = id; + this.values = values; + } + + private BlockState computeDefaultState() { + BlockState defaultState = Iterables.getFirst(getBlockStatesMap().values(), null); + if (values != null) { + defaultState = values.apply(defaultState); + } + return defaultState; + } + + private Map, Object>, BlockState> getBlockStatesMap() { + return blockStatesMap.getValue(); + } + + /** + * Gets the ID of this block. + * + * @return The id + */ + @Override + public String getId() { + return this.id; + } + + public Component getRichName() { + return WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS) + .getRegistries().getBlockRegistry().getRichName(this); + } + + /** + * Gets the name of this block, or the ID if the name cannot be found. + * + * @return The name, or ID + * @deprecated The name is now translatable, use {@link #getRichName()}. + */ + @Deprecated + public String getName() { + String name = this.name.getValue(); + if (name == null || name.isEmpty()) { + return getId(); + } + return name; + } + + /** + * Gets the properties of this BlockType in a {@code key->property} mapping. + * + * @return The properties map + */ + public Map> getPropertyMap() { + return properties.getValue(); + } + + /** + * Gets the properties of this BlockType. + * + * @return the properties + */ + public List> getProperties() { + return ImmutableList.copyOf(this.getPropertyMap().values()); + } + + /** + * Gets a property by name. + * + * @param name The name + * @return The property + */ + public Property getProperty(String name) { + // Assume it works, CCE later at runtime if not. + @SuppressWarnings("unchecked") + Property property = (Property) getPropertyMap().get(name); + checkArgument(property != null, "%s has no property named %s", this, name); + return property; + } + + /** + * Gets the default state of this block type. + * + * @return The default state + */ + public BlockState getDefaultState() { + return defaultState.getValue(); + } + + public FuzzyBlockState getFuzzyMatcher() { + return emptyFuzzy.getValue(); + } + + /** + * Gets a list of all possible states for this BlockType. + * + * @return All possible states + */ + public List getAllStates() { + return ImmutableList.copyOf(getBlockStatesMap().values()); + } + + /** + * Gets a state of this BlockType with the given properties. + * + * @return The state, if it exists + */ + public BlockState getState(Map, Object> key) { + BlockState state = getBlockStatesMap().get(key); + checkArgument(state != null, "%s has no state for %s", this, key); + return state; + } + + /** + * Gets whether this block type has an item representation. + * + * @return If it has an item + */ + public boolean hasItemType() { + return getItemType() != null; + } + + /** + * Gets the item representation of this block type, if it exists. + * + * @return The item representation + */ + @Nullable + public ItemType getItemType() { + return ItemTypes.get(this.id); + } + + /** + * Get the material for this BlockType. + * + * @return The material + */ + public BlockMaterial getMaterial() { + return blockMaterial.getValue(); + } + + /** + * Gets the legacy ID. Needed for legacy reasons. + * + *

+ * DO NOT USE THIS. + *

+ * + * @return legacy id or 0, if unknown + */ + @Deprecated + public int getLegacyId() { + return legacyId.getValue(); + } + + /** + * Gets the legacy data. Needed for legacy reasons. + * + *

+ * DO NOT USE THIS. + *

+ * + * @return legacy data or 0, if unknown + */ + @Deprecated + public int getLegacyData() { + return legacyData.getValue(); + } + + private int computeLegacy(int index) { + int[] legacy = LegacyMapper.getInstance().getLegacyFromBlock(this.getDefaultState()); + return legacy != null ? legacy[index] : 0; + } + + @Override + public String toString() { + return getId(); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof BlockType && this.id.equals(((BlockType) obj).id); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java b/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java new file mode 100644 index 0000000..13bac50 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java @@ -0,0 +1,1047 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.block; + +import javax.annotation.Nullable; + +/** + * Stores a list of common {@link BlockType BlockTypes}. + * + * @see BlockType + */ +@SuppressWarnings("unused") +public final class BlockTypes { + @Nullable public static final BlockType ACACIA_BUTTON = get("minecraft:acacia_button"); + @Nullable public static final BlockType ACACIA_DOOR = get("minecraft:acacia_door"); + @Nullable public static final BlockType ACACIA_FENCE = get("minecraft:acacia_fence"); + @Nullable public static final BlockType ACACIA_FENCE_GATE = get("minecraft:acacia_fence_gate"); + @Nullable public static final BlockType ACACIA_HANGING_SIGN = get("minecraft:acacia_hanging_sign"); + @Nullable public static final BlockType ACACIA_LEAVES = get("minecraft:acacia_leaves"); + @Nullable public static final BlockType ACACIA_LOG = get("minecraft:acacia_log"); + @Nullable public static final BlockType ACACIA_PLANKS = get("minecraft:acacia_planks"); + @Nullable public static final BlockType ACACIA_PRESSURE_PLATE = get("minecraft:acacia_pressure_plate"); + @Nullable public static final BlockType ACACIA_SAPLING = get("minecraft:acacia_sapling"); + @Nullable public static final BlockType ACACIA_SIGN = get("minecraft:acacia_sign"); + @Nullable public static final BlockType ACACIA_SLAB = get("minecraft:acacia_slab"); + @Nullable public static final BlockType ACACIA_STAIRS = get("minecraft:acacia_stairs"); + @Nullable public static final BlockType ACACIA_TRAPDOOR = get("minecraft:acacia_trapdoor"); + @Nullable public static final BlockType ACACIA_WALL_HANGING_SIGN = get("minecraft:acacia_wall_hanging_sign"); + @Nullable public static final BlockType ACACIA_WALL_SIGN = get("minecraft:acacia_wall_sign"); + @Nullable public static final BlockType ACACIA_WOOD = get("minecraft:acacia_wood"); + @Nullable public static final BlockType ACTIVATOR_RAIL = get("minecraft:activator_rail"); + @Nullable public static final BlockType AIR = get("minecraft:air"); + @Nullable public static final BlockType ALLIUM = get("minecraft:allium"); + @Nullable public static final BlockType AMETHYST_BLOCK = get("minecraft:amethyst_block"); + @Nullable public static final BlockType AMETHYST_CLUSTER = get("minecraft:amethyst_cluster"); + @Nullable public static final BlockType ANCIENT_DEBRIS = get("minecraft:ancient_debris"); + @Nullable public static final BlockType ANDESITE = get("minecraft:andesite"); + @Nullable public static final BlockType ANDESITE_SLAB = get("minecraft:andesite_slab"); + @Nullable public static final BlockType ANDESITE_STAIRS = get("minecraft:andesite_stairs"); + @Nullable public static final BlockType ANDESITE_WALL = get("minecraft:andesite_wall"); + @Nullable public static final BlockType ANVIL = get("minecraft:anvil"); + @Nullable public static final BlockType ATTACHED_MELON_STEM = get("minecraft:attached_melon_stem"); + @Nullable public static final BlockType ATTACHED_PUMPKIN_STEM = get("minecraft:attached_pumpkin_stem"); + @Nullable public static final BlockType AZALEA = get("minecraft:azalea"); + @Nullable public static final BlockType AZALEA_LEAVES = get("minecraft:azalea_leaves"); + @Nullable public static final BlockType AZURE_BLUET = get("minecraft:azure_bluet"); + @Nullable public static final BlockType BAMBOO = get("minecraft:bamboo"); + @Nullable public static final BlockType BAMBOO_BLOCK = get("minecraft:bamboo_block"); + @Nullable public static final BlockType BAMBOO_BUTTON = get("minecraft:bamboo_button"); + @Nullable public static final BlockType BAMBOO_DOOR = get("minecraft:bamboo_door"); + @Nullable public static final BlockType BAMBOO_FENCE = get("minecraft:bamboo_fence"); + @Nullable public static final BlockType BAMBOO_FENCE_GATE = get("minecraft:bamboo_fence_gate"); + @Nullable public static final BlockType BAMBOO_HANGING_SIGN = get("minecraft:bamboo_hanging_sign"); + @Nullable public static final BlockType BAMBOO_MOSAIC = get("minecraft:bamboo_mosaic"); + @Nullable public static final BlockType BAMBOO_MOSAIC_SLAB = get("minecraft:bamboo_mosaic_slab"); + @Nullable public static final BlockType BAMBOO_MOSAIC_STAIRS = get("minecraft:bamboo_mosaic_stairs"); + @Nullable public static final BlockType BAMBOO_PLANKS = get("minecraft:bamboo_planks"); + @Nullable public static final BlockType BAMBOO_PRESSURE_PLATE = get("minecraft:bamboo_pressure_plate"); + @Nullable public static final BlockType BAMBOO_SAPLING = get("minecraft:bamboo_sapling"); + @Nullable public static final BlockType BAMBOO_SIGN = get("minecraft:bamboo_sign"); + @Nullable public static final BlockType BAMBOO_SLAB = get("minecraft:bamboo_slab"); + @Nullable public static final BlockType BAMBOO_STAIRS = get("minecraft:bamboo_stairs"); + @Nullable public static final BlockType BAMBOO_TRAPDOOR = get("minecraft:bamboo_trapdoor"); + @Nullable public static final BlockType BAMBOO_WALL_HANGING_SIGN = get("minecraft:bamboo_wall_hanging_sign"); + @Nullable public static final BlockType BAMBOO_WALL_SIGN = get("minecraft:bamboo_wall_sign"); + @Nullable public static final BlockType BARREL = get("minecraft:barrel"); + @Nullable public static final BlockType BARRIER = get("minecraft:barrier"); + @Nullable public static final BlockType BASALT = get("minecraft:basalt"); + @Nullable public static final BlockType BEACON = get("minecraft:beacon"); + @Nullable public static final BlockType BEDROCK = get("minecraft:bedrock"); + @Nullable public static final BlockType BEE_NEST = get("minecraft:bee_nest"); + @Nullable public static final BlockType BEEHIVE = get("minecraft:beehive"); + @Nullable public static final BlockType BEETROOTS = get("minecraft:beetroots"); + @Nullable public static final BlockType BELL = get("minecraft:bell"); + @Nullable public static final BlockType BIG_DRIPLEAF = get("minecraft:big_dripleaf"); + @Nullable public static final BlockType BIG_DRIPLEAF_STEM = get("minecraft:big_dripleaf_stem"); + @Nullable public static final BlockType BIRCH_BUTTON = get("minecraft:birch_button"); + @Nullable public static final BlockType BIRCH_DOOR = get("minecraft:birch_door"); + @Nullable public static final BlockType BIRCH_FENCE = get("minecraft:birch_fence"); + @Nullable public static final BlockType BIRCH_FENCE_GATE = get("minecraft:birch_fence_gate"); + @Nullable public static final BlockType BIRCH_HANGING_SIGN = get("minecraft:birch_hanging_sign"); + @Nullable public static final BlockType BIRCH_LEAVES = get("minecraft:birch_leaves"); + @Nullable public static final BlockType BIRCH_LOG = get("minecraft:birch_log"); + @Nullable public static final BlockType BIRCH_PLANKS = get("minecraft:birch_planks"); + @Nullable public static final BlockType BIRCH_PRESSURE_PLATE = get("minecraft:birch_pressure_plate"); + @Nullable public static final BlockType BIRCH_SAPLING = get("minecraft:birch_sapling"); + @Nullable public static final BlockType BIRCH_SIGN = get("minecraft:birch_sign"); + @Nullable public static final BlockType BIRCH_SLAB = get("minecraft:birch_slab"); + @Nullable public static final BlockType BIRCH_STAIRS = get("minecraft:birch_stairs"); + @Nullable public static final BlockType BIRCH_TRAPDOOR = get("minecraft:birch_trapdoor"); + @Nullable public static final BlockType BIRCH_WALL_HANGING_SIGN = get("minecraft:birch_wall_hanging_sign"); + @Nullable public static final BlockType BIRCH_WALL_SIGN = get("minecraft:birch_wall_sign"); + @Nullable public static final BlockType BIRCH_WOOD = get("minecraft:birch_wood"); + @Nullable public static final BlockType BLACK_BANNER = get("minecraft:black_banner"); + @Nullable public static final BlockType BLACK_BED = get("minecraft:black_bed"); + @Nullable public static final BlockType BLACK_CANDLE = get("minecraft:black_candle"); + @Nullable public static final BlockType BLACK_CANDLE_CAKE = get("minecraft:black_candle_cake"); + @Nullable public static final BlockType BLACK_CARPET = get("minecraft:black_carpet"); + @Nullable public static final BlockType BLACK_CONCRETE = get("minecraft:black_concrete"); + @Nullable public static final BlockType BLACK_CONCRETE_POWDER = get("minecraft:black_concrete_powder"); + @Nullable public static final BlockType BLACK_GLAZED_TERRACOTTA = get("minecraft:black_glazed_terracotta"); + @Nullable public static final BlockType BLACK_SHULKER_BOX = get("minecraft:black_shulker_box"); + @Nullable public static final BlockType BLACK_STAINED_GLASS = get("minecraft:black_stained_glass"); + @Nullable public static final BlockType BLACK_STAINED_GLASS_PANE = get("minecraft:black_stained_glass_pane"); + @Nullable public static final BlockType BLACK_TERRACOTTA = get("minecraft:black_terracotta"); + @Nullable public static final BlockType BLACK_WALL_BANNER = get("minecraft:black_wall_banner"); + @Nullable public static final BlockType BLACK_WOOL = get("minecraft:black_wool"); + @Nullable public static final BlockType BLACKSTONE = get("minecraft:blackstone"); + @Nullable public static final BlockType BLACKSTONE_SLAB = get("minecraft:blackstone_slab"); + @Nullable public static final BlockType BLACKSTONE_STAIRS = get("minecraft:blackstone_stairs"); + @Nullable public static final BlockType BLACKSTONE_WALL = get("minecraft:blackstone_wall"); + @Nullable public static final BlockType BLAST_FURNACE = get("minecraft:blast_furnace"); + @Nullable public static final BlockType BLUE_BANNER = get("minecraft:blue_banner"); + @Nullable public static final BlockType BLUE_BED = get("minecraft:blue_bed"); + @Nullable public static final BlockType BLUE_CANDLE = get("minecraft:blue_candle"); + @Nullable public static final BlockType BLUE_CANDLE_CAKE = get("minecraft:blue_candle_cake"); + @Nullable public static final BlockType BLUE_CARPET = get("minecraft:blue_carpet"); + @Nullable public static final BlockType BLUE_CONCRETE = get("minecraft:blue_concrete"); + @Nullable public static final BlockType BLUE_CONCRETE_POWDER = get("minecraft:blue_concrete_powder"); + @Nullable public static final BlockType BLUE_GLAZED_TERRACOTTA = get("minecraft:blue_glazed_terracotta"); + @Nullable public static final BlockType BLUE_ICE = get("minecraft:blue_ice"); + @Nullable public static final BlockType BLUE_ORCHID = get("minecraft:blue_orchid"); + @Nullable public static final BlockType BLUE_SHULKER_BOX = get("minecraft:blue_shulker_box"); + @Nullable public static final BlockType BLUE_STAINED_GLASS = get("minecraft:blue_stained_glass"); + @Nullable public static final BlockType BLUE_STAINED_GLASS_PANE = get("minecraft:blue_stained_glass_pane"); + @Nullable public static final BlockType BLUE_TERRACOTTA = get("minecraft:blue_terracotta"); + @Nullable public static final BlockType BLUE_WALL_BANNER = get("minecraft:blue_wall_banner"); + @Nullable public static final BlockType BLUE_WOOL = get("minecraft:blue_wool"); + @Nullable public static final BlockType BONE_BLOCK = get("minecraft:bone_block"); + @Nullable public static final BlockType BOOKSHELF = get("minecraft:bookshelf"); + @Nullable public static final BlockType BRAIN_CORAL = get("minecraft:brain_coral"); + @Nullable public static final BlockType BRAIN_CORAL_BLOCK = get("minecraft:brain_coral_block"); + @Nullable public static final BlockType BRAIN_CORAL_FAN = get("minecraft:brain_coral_fan"); + @Nullable public static final BlockType BRAIN_CORAL_WALL_FAN = get("minecraft:brain_coral_wall_fan"); + @Nullable public static final BlockType BREWING_STAND = get("minecraft:brewing_stand"); + @Nullable public static final BlockType BRICK_SLAB = get("minecraft:brick_slab"); + @Nullable public static final BlockType BRICK_STAIRS = get("minecraft:brick_stairs"); + @Nullable public static final BlockType BRICK_WALL = get("minecraft:brick_wall"); + @Nullable public static final BlockType BRICKS = get("minecraft:bricks"); + @Nullable public static final BlockType BROWN_BANNER = get("minecraft:brown_banner"); + @Nullable public static final BlockType BROWN_BED = get("minecraft:brown_bed"); + @Nullable public static final BlockType BROWN_CANDLE = get("minecraft:brown_candle"); + @Nullable public static final BlockType BROWN_CANDLE_CAKE = get("minecraft:brown_candle_cake"); + @Nullable public static final BlockType BROWN_CARPET = get("minecraft:brown_carpet"); + @Nullable public static final BlockType BROWN_CONCRETE = get("minecraft:brown_concrete"); + @Nullable public static final BlockType BROWN_CONCRETE_POWDER = get("minecraft:brown_concrete_powder"); + @Nullable public static final BlockType BROWN_GLAZED_TERRACOTTA = get("minecraft:brown_glazed_terracotta"); + @Nullable public static final BlockType BROWN_MUSHROOM = get("minecraft:brown_mushroom"); + @Nullable public static final BlockType BROWN_MUSHROOM_BLOCK = get("minecraft:brown_mushroom_block"); + @Nullable public static final BlockType BROWN_SHULKER_BOX = get("minecraft:brown_shulker_box"); + @Nullable public static final BlockType BROWN_STAINED_GLASS = get("minecraft:brown_stained_glass"); + @Nullable public static final BlockType BROWN_STAINED_GLASS_PANE = get("minecraft:brown_stained_glass_pane"); + @Nullable public static final BlockType BROWN_TERRACOTTA = get("minecraft:brown_terracotta"); + @Nullable public static final BlockType BROWN_WALL_BANNER = get("minecraft:brown_wall_banner"); + @Nullable public static final BlockType BROWN_WOOL = get("minecraft:brown_wool"); + @Nullable public static final BlockType BUBBLE_COLUMN = get("minecraft:bubble_column"); + @Nullable public static final BlockType BUBBLE_CORAL = get("minecraft:bubble_coral"); + @Nullable public static final BlockType BUBBLE_CORAL_BLOCK = get("minecraft:bubble_coral_block"); + @Nullable public static final BlockType BUBBLE_CORAL_FAN = get("minecraft:bubble_coral_fan"); + @Nullable public static final BlockType BUBBLE_CORAL_WALL_FAN = get("minecraft:bubble_coral_wall_fan"); + @Nullable public static final BlockType BUDDING_AMETHYST = get("minecraft:budding_amethyst"); + @Nullable public static final BlockType CACTUS = get("minecraft:cactus"); + @Nullable public static final BlockType CAKE = get("minecraft:cake"); + @Nullable public static final BlockType CALCITE = get("minecraft:calcite"); + @Nullable public static final BlockType CALIBRATED_SCULK_SENSOR = get("minecraft:calibrated_sculk_sensor"); + @Nullable public static final BlockType CAMPFIRE = get("minecraft:campfire"); + @Nullable public static final BlockType CANDLE = get("minecraft:candle"); + @Nullable public static final BlockType CANDLE_CAKE = get("minecraft:candle_cake"); + @Nullable public static final BlockType CARROTS = get("minecraft:carrots"); + @Nullable public static final BlockType CARTOGRAPHY_TABLE = get("minecraft:cartography_table"); + @Nullable public static final BlockType CARVED_PUMPKIN = get("minecraft:carved_pumpkin"); + @Nullable public static final BlockType CAULDRON = get("minecraft:cauldron"); + @Nullable public static final BlockType CAVE_AIR = get("minecraft:cave_air"); + @Nullable public static final BlockType CAVE_VINES = get("minecraft:cave_vines"); + @Nullable public static final BlockType CAVE_VINES_PLANT = get("minecraft:cave_vines_plant"); + @Nullable public static final BlockType CHAIN = get("minecraft:chain"); + @Nullable public static final BlockType CHAIN_COMMAND_BLOCK = get("minecraft:chain_command_block"); + @Nullable public static final BlockType CHERRY_BUTTON = get("minecraft:cherry_button"); + @Nullable public static final BlockType CHERRY_DOOR = get("minecraft:cherry_door"); + @Nullable public static final BlockType CHERRY_FENCE = get("minecraft:cherry_fence"); + @Nullable public static final BlockType CHERRY_FENCE_GATE = get("minecraft:cherry_fence_gate"); + @Nullable public static final BlockType CHERRY_HANGING_SIGN = get("minecraft:cherry_hanging_sign"); + @Nullable public static final BlockType CHERRY_LEAVES = get("minecraft:cherry_leaves"); + @Nullable public static final BlockType CHERRY_LOG = get("minecraft:cherry_log"); + @Nullable public static final BlockType CHERRY_PLANKS = get("minecraft:cherry_planks"); + @Nullable public static final BlockType CHERRY_PRESSURE_PLATE = get("minecraft:cherry_pressure_plate"); + @Nullable public static final BlockType CHERRY_SAPLING = get("minecraft:cherry_sapling"); + @Nullable public static final BlockType CHERRY_SIGN = get("minecraft:cherry_sign"); + @Nullable public static final BlockType CHERRY_SLAB = get("minecraft:cherry_slab"); + @Nullable public static final BlockType CHERRY_STAIRS = get("minecraft:cherry_stairs"); + @Nullable public static final BlockType CHERRY_TRAPDOOR = get("minecraft:cherry_trapdoor"); + @Nullable public static final BlockType CHERRY_WALL_HANGING_SIGN = get("minecraft:cherry_wall_hanging_sign"); + @Nullable public static final BlockType CHERRY_WALL_SIGN = get("minecraft:cherry_wall_sign"); + @Nullable public static final BlockType CHERRY_WOOD = get("minecraft:cherry_wood"); + @Nullable public static final BlockType CHEST = get("minecraft:chest"); + @Nullable public static final BlockType CHIPPED_ANVIL = get("minecraft:chipped_anvil"); + @Nullable public static final BlockType CHISELED_BOOKSHELF = get("minecraft:chiseled_bookshelf"); + @Nullable public static final BlockType CHISELED_DEEPSLATE = get("minecraft:chiseled_deepslate"); + @Nullable public static final BlockType CHISELED_NETHER_BRICKS = get("minecraft:chiseled_nether_bricks"); + @Nullable public static final BlockType CHISELED_POLISHED_BLACKSTONE = get("minecraft:chiseled_polished_blackstone"); + @Nullable public static final BlockType CHISELED_QUARTZ_BLOCK = get("minecraft:chiseled_quartz_block"); + @Nullable public static final BlockType CHISELED_RED_SANDSTONE = get("minecraft:chiseled_red_sandstone"); + @Nullable public static final BlockType CHISELED_SANDSTONE = get("minecraft:chiseled_sandstone"); + @Nullable public static final BlockType CHISELED_STONE_BRICKS = get("minecraft:chiseled_stone_bricks"); + @Nullable public static final BlockType CHORUS_FLOWER = get("minecraft:chorus_flower"); + @Nullable public static final BlockType CHORUS_PLANT = get("minecraft:chorus_plant"); + @Nullable public static final BlockType CLAY = get("minecraft:clay"); + @Nullable public static final BlockType COAL_BLOCK = get("minecraft:coal_block"); + @Nullable public static final BlockType COAL_ORE = get("minecraft:coal_ore"); + @Nullable public static final BlockType COARSE_DIRT = get("minecraft:coarse_dirt"); + @Nullable public static final BlockType COBBLED_DEEPSLATE = get("minecraft:cobbled_deepslate"); + @Nullable public static final BlockType COBBLED_DEEPSLATE_SLAB = get("minecraft:cobbled_deepslate_slab"); + @Nullable public static final BlockType COBBLED_DEEPSLATE_STAIRS = get("minecraft:cobbled_deepslate_stairs"); + @Nullable public static final BlockType COBBLED_DEEPSLATE_WALL = get("minecraft:cobbled_deepslate_wall"); + @Nullable public static final BlockType COBBLESTONE = get("minecraft:cobblestone"); + @Nullable public static final BlockType COBBLESTONE_SLAB = get("minecraft:cobblestone_slab"); + @Nullable public static final BlockType COBBLESTONE_STAIRS = get("minecraft:cobblestone_stairs"); + @Nullable public static final BlockType COBBLESTONE_WALL = get("minecraft:cobblestone_wall"); + @Nullable public static final BlockType COBWEB = get("minecraft:cobweb"); + @Nullable public static final BlockType COCOA = get("minecraft:cocoa"); + @Nullable public static final BlockType COMMAND_BLOCK = get("minecraft:command_block"); + @Nullable public static final BlockType COMPARATOR = get("minecraft:comparator"); + @Nullable public static final BlockType COMPOSTER = get("minecraft:composter"); + @Nullable public static final BlockType CONDUIT = get("minecraft:conduit"); + @Nullable public static final BlockType COPPER_BLOCK = get("minecraft:copper_block"); + @Nullable public static final BlockType COPPER_ORE = get("minecraft:copper_ore"); + @Nullable public static final BlockType CORNFLOWER = get("minecraft:cornflower"); + @Nullable public static final BlockType CRACKED_DEEPSLATE_BRICKS = get("minecraft:cracked_deepslate_bricks"); + @Nullable public static final BlockType CRACKED_DEEPSLATE_TILES = get("minecraft:cracked_deepslate_tiles"); + @Nullable public static final BlockType CRACKED_NETHER_BRICKS = get("minecraft:cracked_nether_bricks"); + @Nullable public static final BlockType CRACKED_POLISHED_BLACKSTONE_BRICKS = get("minecraft:cracked_polished_blackstone_bricks"); + @Nullable public static final BlockType CRACKED_STONE_BRICKS = get("minecraft:cracked_stone_bricks"); + @Nullable public static final BlockType CRAFTING_TABLE = get("minecraft:crafting_table"); + @Nullable public static final BlockType CREEPER_HEAD = get("minecraft:creeper_head"); + @Nullable public static final BlockType CREEPER_WALL_HEAD = get("minecraft:creeper_wall_head"); + @Nullable public static final BlockType CRIMSON_BUTTON = get("minecraft:crimson_button"); + @Nullable public static final BlockType CRIMSON_DOOR = get("minecraft:crimson_door"); + @Nullable public static final BlockType CRIMSON_FENCE = get("minecraft:crimson_fence"); + @Nullable public static final BlockType CRIMSON_FENCE_GATE = get("minecraft:crimson_fence_gate"); + @Nullable public static final BlockType CRIMSON_FUNGUS = get("minecraft:crimson_fungus"); + @Nullable public static final BlockType CRIMSON_HANGING_SIGN = get("minecraft:crimson_hanging_sign"); + @Nullable public static final BlockType CRIMSON_HYPHAE = get("minecraft:crimson_hyphae"); + @Nullable public static final BlockType CRIMSON_NYLIUM = get("minecraft:crimson_nylium"); + @Nullable public static final BlockType CRIMSON_PLANKS = get("minecraft:crimson_planks"); + @Nullable public static final BlockType CRIMSON_PRESSURE_PLATE = get("minecraft:crimson_pressure_plate"); + @Nullable public static final BlockType CRIMSON_ROOTS = get("minecraft:crimson_roots"); + @Nullable public static final BlockType CRIMSON_SIGN = get("minecraft:crimson_sign"); + @Nullable public static final BlockType CRIMSON_SLAB = get("minecraft:crimson_slab"); + @Nullable public static final BlockType CRIMSON_STAIRS = get("minecraft:crimson_stairs"); + @Nullable public static final BlockType CRIMSON_STEM = get("minecraft:crimson_stem"); + @Nullable public static final BlockType CRIMSON_TRAPDOOR = get("minecraft:crimson_trapdoor"); + @Nullable public static final BlockType CRIMSON_WALL_HANGING_SIGN = get("minecraft:crimson_wall_hanging_sign"); + @Nullable public static final BlockType CRIMSON_WALL_SIGN = get("minecraft:crimson_wall_sign"); + @Nullable public static final BlockType CRYING_OBSIDIAN = get("minecraft:crying_obsidian"); + @Nullable public static final BlockType CUT_COPPER = get("minecraft:cut_copper"); + @Nullable public static final BlockType CUT_COPPER_SLAB = get("minecraft:cut_copper_slab"); + @Nullable public static final BlockType CUT_COPPER_STAIRS = get("minecraft:cut_copper_stairs"); + @Nullable public static final BlockType CUT_RED_SANDSTONE = get("minecraft:cut_red_sandstone"); + @Nullable public static final BlockType CUT_RED_SANDSTONE_SLAB = get("minecraft:cut_red_sandstone_slab"); + @Nullable public static final BlockType CUT_SANDSTONE = get("minecraft:cut_sandstone"); + @Nullable public static final BlockType CUT_SANDSTONE_SLAB = get("minecraft:cut_sandstone_slab"); + @Nullable public static final BlockType CYAN_BANNER = get("minecraft:cyan_banner"); + @Nullable public static final BlockType CYAN_BED = get("minecraft:cyan_bed"); + @Nullable public static final BlockType CYAN_CANDLE = get("minecraft:cyan_candle"); + @Nullable public static final BlockType CYAN_CANDLE_CAKE = get("minecraft:cyan_candle_cake"); + @Nullable public static final BlockType CYAN_CARPET = get("minecraft:cyan_carpet"); + @Nullable public static final BlockType CYAN_CONCRETE = get("minecraft:cyan_concrete"); + @Nullable public static final BlockType CYAN_CONCRETE_POWDER = get("minecraft:cyan_concrete_powder"); + @Nullable public static final BlockType CYAN_GLAZED_TERRACOTTA = get("minecraft:cyan_glazed_terracotta"); + @Nullable public static final BlockType CYAN_SHULKER_BOX = get("minecraft:cyan_shulker_box"); + @Nullable public static final BlockType CYAN_STAINED_GLASS = get("minecraft:cyan_stained_glass"); + @Nullable public static final BlockType CYAN_STAINED_GLASS_PANE = get("minecraft:cyan_stained_glass_pane"); + @Nullable public static final BlockType CYAN_TERRACOTTA = get("minecraft:cyan_terracotta"); + @Nullable public static final BlockType CYAN_WALL_BANNER = get("minecraft:cyan_wall_banner"); + @Nullable public static final BlockType CYAN_WOOL = get("minecraft:cyan_wool"); + @Nullable public static final BlockType DAMAGED_ANVIL = get("minecraft:damaged_anvil"); + @Nullable public static final BlockType DANDELION = get("minecraft:dandelion"); + @Nullable public static final BlockType DARK_OAK_BUTTON = get("minecraft:dark_oak_button"); + @Nullable public static final BlockType DARK_OAK_DOOR = get("minecraft:dark_oak_door"); + @Nullable public static final BlockType DARK_OAK_FENCE = get("minecraft:dark_oak_fence"); + @Nullable public static final BlockType DARK_OAK_FENCE_GATE = get("minecraft:dark_oak_fence_gate"); + @Nullable public static final BlockType DARK_OAK_HANGING_SIGN = get("minecraft:dark_oak_hanging_sign"); + @Nullable public static final BlockType DARK_OAK_LEAVES = get("minecraft:dark_oak_leaves"); + @Nullable public static final BlockType DARK_OAK_LOG = get("minecraft:dark_oak_log"); + @Nullable public static final BlockType DARK_OAK_PLANKS = get("minecraft:dark_oak_planks"); + @Nullable public static final BlockType DARK_OAK_PRESSURE_PLATE = get("minecraft:dark_oak_pressure_plate"); + @Nullable public static final BlockType DARK_OAK_SAPLING = get("minecraft:dark_oak_sapling"); + @Nullable public static final BlockType DARK_OAK_SIGN = get("minecraft:dark_oak_sign"); + @Nullable public static final BlockType DARK_OAK_SLAB = get("minecraft:dark_oak_slab"); + @Nullable public static final BlockType DARK_OAK_STAIRS = get("minecraft:dark_oak_stairs"); + @Nullable public static final BlockType DARK_OAK_TRAPDOOR = get("minecraft:dark_oak_trapdoor"); + @Nullable public static final BlockType DARK_OAK_WALL_HANGING_SIGN = get("minecraft:dark_oak_wall_hanging_sign"); + @Nullable public static final BlockType DARK_OAK_WALL_SIGN = get("minecraft:dark_oak_wall_sign"); + @Nullable public static final BlockType DARK_OAK_WOOD = get("minecraft:dark_oak_wood"); + @Nullable public static final BlockType DARK_PRISMARINE = get("minecraft:dark_prismarine"); + @Nullable public static final BlockType DARK_PRISMARINE_SLAB = get("minecraft:dark_prismarine_slab"); + @Nullable public static final BlockType DARK_PRISMARINE_STAIRS = get("minecraft:dark_prismarine_stairs"); + @Nullable public static final BlockType DAYLIGHT_DETECTOR = get("minecraft:daylight_detector"); + @Nullable public static final BlockType DEAD_BRAIN_CORAL = get("minecraft:dead_brain_coral"); + @Nullable public static final BlockType DEAD_BRAIN_CORAL_BLOCK = get("minecraft:dead_brain_coral_block"); + @Nullable public static final BlockType DEAD_BRAIN_CORAL_FAN = get("minecraft:dead_brain_coral_fan"); + @Nullable public static final BlockType DEAD_BRAIN_CORAL_WALL_FAN = get("minecraft:dead_brain_coral_wall_fan"); + @Nullable public static final BlockType DEAD_BUBBLE_CORAL = get("minecraft:dead_bubble_coral"); + @Nullable public static final BlockType DEAD_BUBBLE_CORAL_BLOCK = get("minecraft:dead_bubble_coral_block"); + @Nullable public static final BlockType DEAD_BUBBLE_CORAL_FAN = get("minecraft:dead_bubble_coral_fan"); + @Nullable public static final BlockType DEAD_BUBBLE_CORAL_WALL_FAN = get("minecraft:dead_bubble_coral_wall_fan"); + @Nullable public static final BlockType DEAD_BUSH = get("minecraft:dead_bush"); + @Nullable public static final BlockType DEAD_FIRE_CORAL = get("minecraft:dead_fire_coral"); + @Nullable public static final BlockType DEAD_FIRE_CORAL_BLOCK = get("minecraft:dead_fire_coral_block"); + @Nullable public static final BlockType DEAD_FIRE_CORAL_FAN = get("minecraft:dead_fire_coral_fan"); + @Nullable public static final BlockType DEAD_FIRE_CORAL_WALL_FAN = get("minecraft:dead_fire_coral_wall_fan"); + @Nullable public static final BlockType DEAD_HORN_CORAL = get("minecraft:dead_horn_coral"); + @Nullable public static final BlockType DEAD_HORN_CORAL_BLOCK = get("minecraft:dead_horn_coral_block"); + @Nullable public static final BlockType DEAD_HORN_CORAL_FAN = get("minecraft:dead_horn_coral_fan"); + @Nullable public static final BlockType DEAD_HORN_CORAL_WALL_FAN = get("minecraft:dead_horn_coral_wall_fan"); + @Nullable public static final BlockType DEAD_TUBE_CORAL = get("minecraft:dead_tube_coral"); + @Nullable public static final BlockType DEAD_TUBE_CORAL_BLOCK = get("minecraft:dead_tube_coral_block"); + @Nullable public static final BlockType DEAD_TUBE_CORAL_FAN = get("minecraft:dead_tube_coral_fan"); + @Nullable public static final BlockType DEAD_TUBE_CORAL_WALL_FAN = get("minecraft:dead_tube_coral_wall_fan"); + @Nullable public static final BlockType DECORATED_POT = get("minecraft:decorated_pot"); + @Nullable public static final BlockType DEEPSLATE = get("minecraft:deepslate"); + @Nullable public static final BlockType DEEPSLATE_BRICK_SLAB = get("minecraft:deepslate_brick_slab"); + @Nullable public static final BlockType DEEPSLATE_BRICK_STAIRS = get("minecraft:deepslate_brick_stairs"); + @Nullable public static final BlockType DEEPSLATE_BRICK_WALL = get("minecraft:deepslate_brick_wall"); + @Nullable public static final BlockType DEEPSLATE_BRICKS = get("minecraft:deepslate_bricks"); + @Nullable public static final BlockType DEEPSLATE_COAL_ORE = get("minecraft:deepslate_coal_ore"); + @Nullable public static final BlockType DEEPSLATE_COPPER_ORE = get("minecraft:deepslate_copper_ore"); + @Nullable public static final BlockType DEEPSLATE_DIAMOND_ORE = get("minecraft:deepslate_diamond_ore"); + @Nullable public static final BlockType DEEPSLATE_EMERALD_ORE = get("minecraft:deepslate_emerald_ore"); + @Nullable public static final BlockType DEEPSLATE_GOLD_ORE = get("minecraft:deepslate_gold_ore"); + @Nullable public static final BlockType DEEPSLATE_IRON_ORE = get("minecraft:deepslate_iron_ore"); + @Nullable public static final BlockType DEEPSLATE_LAPIS_ORE = get("minecraft:deepslate_lapis_ore"); + @Nullable public static final BlockType DEEPSLATE_REDSTONE_ORE = get("minecraft:deepslate_redstone_ore"); + @Nullable public static final BlockType DEEPSLATE_TILE_SLAB = get("minecraft:deepslate_tile_slab"); + @Nullable public static final BlockType DEEPSLATE_TILE_STAIRS = get("minecraft:deepslate_tile_stairs"); + @Nullable public static final BlockType DEEPSLATE_TILE_WALL = get("minecraft:deepslate_tile_wall"); + @Nullable public static final BlockType DEEPSLATE_TILES = get("minecraft:deepslate_tiles"); + @Nullable public static final BlockType DETECTOR_RAIL = get("minecraft:detector_rail"); + @Nullable public static final BlockType DIAMOND_BLOCK = get("minecraft:diamond_block"); + @Nullable public static final BlockType DIAMOND_ORE = get("minecraft:diamond_ore"); + @Nullable public static final BlockType DIORITE = get("minecraft:diorite"); + @Nullable public static final BlockType DIORITE_SLAB = get("minecraft:diorite_slab"); + @Nullable public static final BlockType DIORITE_STAIRS = get("minecraft:diorite_stairs"); + @Nullable public static final BlockType DIORITE_WALL = get("minecraft:diorite_wall"); + @Nullable public static final BlockType DIRT = get("minecraft:dirt"); + @Nullable public static final BlockType DIRT_PATH = get("minecraft:dirt_path"); + @Nullable public static final BlockType DISPENSER = get("minecraft:dispenser"); + @Nullable public static final BlockType DRAGON_EGG = get("minecraft:dragon_egg"); + @Nullable public static final BlockType DRAGON_HEAD = get("minecraft:dragon_head"); + @Nullable public static final BlockType DRAGON_WALL_HEAD = get("minecraft:dragon_wall_head"); + @Nullable public static final BlockType DRIED_KELP_BLOCK = get("minecraft:dried_kelp_block"); + @Nullable public static final BlockType DRIPSTONE_BLOCK = get("minecraft:dripstone_block"); + @Nullable public static final BlockType DROPPER = get("minecraft:dropper"); + @Nullable public static final BlockType EMERALD_BLOCK = get("minecraft:emerald_block"); + @Nullable public static final BlockType EMERALD_ORE = get("minecraft:emerald_ore"); + @Nullable public static final BlockType ENCHANTING_TABLE = get("minecraft:enchanting_table"); + @Nullable public static final BlockType END_GATEWAY = get("minecraft:end_gateway"); + @Nullable public static final BlockType END_PORTAL = get("minecraft:end_portal"); + @Nullable public static final BlockType END_PORTAL_FRAME = get("minecraft:end_portal_frame"); + @Nullable public static final BlockType END_ROD = get("minecraft:end_rod"); + @Nullable public static final BlockType END_STONE = get("minecraft:end_stone"); + @Nullable public static final BlockType END_STONE_BRICK_SLAB = get("minecraft:end_stone_brick_slab"); + @Nullable public static final BlockType END_STONE_BRICK_STAIRS = get("minecraft:end_stone_brick_stairs"); + @Nullable public static final BlockType END_STONE_BRICK_WALL = get("minecraft:end_stone_brick_wall"); + @Nullable public static final BlockType END_STONE_BRICKS = get("minecraft:end_stone_bricks"); + @Nullable public static final BlockType ENDER_CHEST = get("minecraft:ender_chest"); + @Nullable public static final BlockType EXPOSED_COPPER = get("minecraft:exposed_copper"); + @Nullable public static final BlockType EXPOSED_CUT_COPPER = get("minecraft:exposed_cut_copper"); + @Nullable public static final BlockType EXPOSED_CUT_COPPER_SLAB = get("minecraft:exposed_cut_copper_slab"); + @Nullable public static final BlockType EXPOSED_CUT_COPPER_STAIRS = get("minecraft:exposed_cut_copper_stairs"); + @Nullable public static final BlockType FARMLAND = get("minecraft:farmland"); + @Nullable public static final BlockType FERN = get("minecraft:fern"); + @Nullable public static final BlockType FIRE = get("minecraft:fire"); + @Nullable public static final BlockType FIRE_CORAL = get("minecraft:fire_coral"); + @Nullable public static final BlockType FIRE_CORAL_BLOCK = get("minecraft:fire_coral_block"); + @Nullable public static final BlockType FIRE_CORAL_FAN = get("minecraft:fire_coral_fan"); + @Nullable public static final BlockType FIRE_CORAL_WALL_FAN = get("minecraft:fire_coral_wall_fan"); + @Nullable public static final BlockType FLETCHING_TABLE = get("minecraft:fletching_table"); + @Nullable public static final BlockType FLOWER_POT = get("minecraft:flower_pot"); + @Nullable public static final BlockType FLOWERING_AZALEA = get("minecraft:flowering_azalea"); + @Nullable public static final BlockType FLOWERING_AZALEA_LEAVES = get("minecraft:flowering_azalea_leaves"); + @Nullable public static final BlockType FROGSPAWN = get("minecraft:frogspawn"); + @Nullable public static final BlockType FROSTED_ICE = get("minecraft:frosted_ice"); + @Nullable public static final BlockType FURNACE = get("minecraft:furnace"); + @Nullable public static final BlockType GILDED_BLACKSTONE = get("minecraft:gilded_blackstone"); + @Nullable public static final BlockType GLASS = get("minecraft:glass"); + @Nullable public static final BlockType GLASS_PANE = get("minecraft:glass_pane"); + @Nullable public static final BlockType GLOW_LICHEN = get("minecraft:glow_lichen"); + @Nullable public static final BlockType GLOWSTONE = get("minecraft:glowstone"); + @Nullable public static final BlockType GOLD_BLOCK = get("minecraft:gold_block"); + @Nullable public static final BlockType GOLD_ORE = get("minecraft:gold_ore"); + @Nullable public static final BlockType GRANITE = get("minecraft:granite"); + @Nullable public static final BlockType GRANITE_SLAB = get("minecraft:granite_slab"); + @Nullable public static final BlockType GRANITE_STAIRS = get("minecraft:granite_stairs"); + @Nullable public static final BlockType GRANITE_WALL = get("minecraft:granite_wall"); + @Nullable public static final BlockType GRASS = get("minecraft:grass"); + @Nullable public static final BlockType GRASS_BLOCK = get("minecraft:grass_block"); + @Deprecated @Nullable public static final BlockType GRASS_PATH = get("minecraft:grass_path"); + @Nullable public static final BlockType GRAVEL = get("minecraft:gravel"); + @Nullable public static final BlockType GRAY_BANNER = get("minecraft:gray_banner"); + @Nullable public static final BlockType GRAY_BED = get("minecraft:gray_bed"); + @Nullable public static final BlockType GRAY_CANDLE = get("minecraft:gray_candle"); + @Nullable public static final BlockType GRAY_CANDLE_CAKE = get("minecraft:gray_candle_cake"); + @Nullable public static final BlockType GRAY_CARPET = get("minecraft:gray_carpet"); + @Nullable public static final BlockType GRAY_CONCRETE = get("minecraft:gray_concrete"); + @Nullable public static final BlockType GRAY_CONCRETE_POWDER = get("minecraft:gray_concrete_powder"); + @Nullable public static final BlockType GRAY_GLAZED_TERRACOTTA = get("minecraft:gray_glazed_terracotta"); + @Nullable public static final BlockType GRAY_SHULKER_BOX = get("minecraft:gray_shulker_box"); + @Nullable public static final BlockType GRAY_STAINED_GLASS = get("minecraft:gray_stained_glass"); + @Nullable public static final BlockType GRAY_STAINED_GLASS_PANE = get("minecraft:gray_stained_glass_pane"); + @Nullable public static final BlockType GRAY_TERRACOTTA = get("minecraft:gray_terracotta"); + @Nullable public static final BlockType GRAY_WALL_BANNER = get("minecraft:gray_wall_banner"); + @Nullable public static final BlockType GRAY_WOOL = get("minecraft:gray_wool"); + @Nullable public static final BlockType GREEN_BANNER = get("minecraft:green_banner"); + @Nullable public static final BlockType GREEN_BED = get("minecraft:green_bed"); + @Nullable public static final BlockType GREEN_CANDLE = get("minecraft:green_candle"); + @Nullable public static final BlockType GREEN_CANDLE_CAKE = get("minecraft:green_candle_cake"); + @Nullable public static final BlockType GREEN_CARPET = get("minecraft:green_carpet"); + @Nullable public static final BlockType GREEN_CONCRETE = get("minecraft:green_concrete"); + @Nullable public static final BlockType GREEN_CONCRETE_POWDER = get("minecraft:green_concrete_powder"); + @Nullable public static final BlockType GREEN_GLAZED_TERRACOTTA = get("minecraft:green_glazed_terracotta"); + @Nullable public static final BlockType GREEN_SHULKER_BOX = get("minecraft:green_shulker_box"); + @Nullable public static final BlockType GREEN_STAINED_GLASS = get("minecraft:green_stained_glass"); + @Nullable public static final BlockType GREEN_STAINED_GLASS_PANE = get("minecraft:green_stained_glass_pane"); + @Nullable public static final BlockType GREEN_TERRACOTTA = get("minecraft:green_terracotta"); + @Nullable public static final BlockType GREEN_WALL_BANNER = get("minecraft:green_wall_banner"); + @Nullable public static final BlockType GREEN_WOOL = get("minecraft:green_wool"); + @Nullable public static final BlockType GRINDSTONE = get("minecraft:grindstone"); + @Nullable public static final BlockType HANGING_ROOTS = get("minecraft:hanging_roots"); + @Nullable public static final BlockType HAY_BLOCK = get("minecraft:hay_block"); + @Nullable public static final BlockType HEAVY_WEIGHTED_PRESSURE_PLATE = get("minecraft:heavy_weighted_pressure_plate"); + @Nullable public static final BlockType HONEY_BLOCK = get("minecraft:honey_block"); + @Nullable public static final BlockType HONEYCOMB_BLOCK = get("minecraft:honeycomb_block"); + @Nullable public static final BlockType HOPPER = get("minecraft:hopper"); + @Nullable public static final BlockType HORN_CORAL = get("minecraft:horn_coral"); + @Nullable public static final BlockType HORN_CORAL_BLOCK = get("minecraft:horn_coral_block"); + @Nullable public static final BlockType HORN_CORAL_FAN = get("minecraft:horn_coral_fan"); + @Nullable public static final BlockType HORN_CORAL_WALL_FAN = get("minecraft:horn_coral_wall_fan"); + @Nullable public static final BlockType ICE = get("minecraft:ice"); + @Nullable public static final BlockType INFESTED_CHISELED_STONE_BRICKS = get("minecraft:infested_chiseled_stone_bricks"); + @Nullable public static final BlockType INFESTED_COBBLESTONE = get("minecraft:infested_cobblestone"); + @Nullable public static final BlockType INFESTED_CRACKED_STONE_BRICKS = get("minecraft:infested_cracked_stone_bricks"); + @Nullable public static final BlockType INFESTED_DEEPSLATE = get("minecraft:infested_deepslate"); + @Nullable public static final BlockType INFESTED_MOSSY_STONE_BRICKS = get("minecraft:infested_mossy_stone_bricks"); + @Nullable public static final BlockType INFESTED_STONE = get("minecraft:infested_stone"); + @Nullable public static final BlockType INFESTED_STONE_BRICKS = get("minecraft:infested_stone_bricks"); + @Nullable public static final BlockType IRON_BARS = get("minecraft:iron_bars"); + @Nullable public static final BlockType IRON_BLOCK = get("minecraft:iron_block"); + @Nullable public static final BlockType IRON_DOOR = get("minecraft:iron_door"); + @Nullable public static final BlockType IRON_ORE = get("minecraft:iron_ore"); + @Nullable public static final BlockType IRON_TRAPDOOR = get("minecraft:iron_trapdoor"); + @Nullable public static final BlockType JACK_O_LANTERN = get("minecraft:jack_o_lantern"); + @Nullable public static final BlockType JIGSAW = get("minecraft:jigsaw"); + @Nullable public static final BlockType JUKEBOX = get("minecraft:jukebox"); + @Nullable public static final BlockType JUNGLE_BUTTON = get("minecraft:jungle_button"); + @Nullable public static final BlockType JUNGLE_DOOR = get("minecraft:jungle_door"); + @Nullable public static final BlockType JUNGLE_FENCE = get("minecraft:jungle_fence"); + @Nullable public static final BlockType JUNGLE_FENCE_GATE = get("minecraft:jungle_fence_gate"); + @Nullable public static final BlockType JUNGLE_HANGING_SIGN = get("minecraft:jungle_hanging_sign"); + @Nullable public static final BlockType JUNGLE_LEAVES = get("minecraft:jungle_leaves"); + @Nullable public static final BlockType JUNGLE_LOG = get("minecraft:jungle_log"); + @Nullable public static final BlockType JUNGLE_PLANKS = get("minecraft:jungle_planks"); + @Nullable public static final BlockType JUNGLE_PRESSURE_PLATE = get("minecraft:jungle_pressure_plate"); + @Nullable public static final BlockType JUNGLE_SAPLING = get("minecraft:jungle_sapling"); + @Nullable public static final BlockType JUNGLE_SIGN = get("minecraft:jungle_sign"); + @Nullable public static final BlockType JUNGLE_SLAB = get("minecraft:jungle_slab"); + @Nullable public static final BlockType JUNGLE_STAIRS = get("minecraft:jungle_stairs"); + @Nullable public static final BlockType JUNGLE_TRAPDOOR = get("minecraft:jungle_trapdoor"); + @Nullable public static final BlockType JUNGLE_WALL_HANGING_SIGN = get("minecraft:jungle_wall_hanging_sign"); + @Nullable public static final BlockType JUNGLE_WALL_SIGN = get("minecraft:jungle_wall_sign"); + @Nullable public static final BlockType JUNGLE_WOOD = get("minecraft:jungle_wood"); + @Nullable public static final BlockType KELP = get("minecraft:kelp"); + @Nullable public static final BlockType KELP_PLANT = get("minecraft:kelp_plant"); + @Nullable public static final BlockType LADDER = get("minecraft:ladder"); + @Nullable public static final BlockType LANTERN = get("minecraft:lantern"); + @Nullable public static final BlockType LAPIS_BLOCK = get("minecraft:lapis_block"); + @Nullable public static final BlockType LAPIS_ORE = get("minecraft:lapis_ore"); + @Nullable public static final BlockType LARGE_AMETHYST_BUD = get("minecraft:large_amethyst_bud"); + @Nullable public static final BlockType LARGE_FERN = get("minecraft:large_fern"); + @Nullable public static final BlockType LAVA = get("minecraft:lava"); + @Nullable public static final BlockType LAVA_CAULDRON = get("minecraft:lava_cauldron"); + @Nullable public static final BlockType LECTERN = get("minecraft:lectern"); + @Nullable public static final BlockType LEVER = get("minecraft:lever"); + @Nullable public static final BlockType LIGHT = get("minecraft:light"); + @Nullable public static final BlockType LIGHT_BLUE_BANNER = get("minecraft:light_blue_banner"); + @Nullable public static final BlockType LIGHT_BLUE_BED = get("minecraft:light_blue_bed"); + @Nullable public static final BlockType LIGHT_BLUE_CANDLE = get("minecraft:light_blue_candle"); + @Nullable public static final BlockType LIGHT_BLUE_CANDLE_CAKE = get("minecraft:light_blue_candle_cake"); + @Nullable public static final BlockType LIGHT_BLUE_CARPET = get("minecraft:light_blue_carpet"); + @Nullable public static final BlockType LIGHT_BLUE_CONCRETE = get("minecraft:light_blue_concrete"); + @Nullable public static final BlockType LIGHT_BLUE_CONCRETE_POWDER = get("minecraft:light_blue_concrete_powder"); + @Nullable public static final BlockType LIGHT_BLUE_GLAZED_TERRACOTTA = get("minecraft:light_blue_glazed_terracotta"); + @Nullable public static final BlockType LIGHT_BLUE_SHULKER_BOX = get("minecraft:light_blue_shulker_box"); + @Nullable public static final BlockType LIGHT_BLUE_STAINED_GLASS = get("minecraft:light_blue_stained_glass"); + @Nullable public static final BlockType LIGHT_BLUE_STAINED_GLASS_PANE = get("minecraft:light_blue_stained_glass_pane"); + @Nullable public static final BlockType LIGHT_BLUE_TERRACOTTA = get("minecraft:light_blue_terracotta"); + @Nullable public static final BlockType LIGHT_BLUE_WALL_BANNER = get("minecraft:light_blue_wall_banner"); + @Nullable public static final BlockType LIGHT_BLUE_WOOL = get("minecraft:light_blue_wool"); + @Nullable public static final BlockType LIGHT_GRAY_BANNER = get("minecraft:light_gray_banner"); + @Nullable public static final BlockType LIGHT_GRAY_BED = get("minecraft:light_gray_bed"); + @Nullable public static final BlockType LIGHT_GRAY_CANDLE = get("minecraft:light_gray_candle"); + @Nullable public static final BlockType LIGHT_GRAY_CANDLE_CAKE = get("minecraft:light_gray_candle_cake"); + @Nullable public static final BlockType LIGHT_GRAY_CARPET = get("minecraft:light_gray_carpet"); + @Nullable public static final BlockType LIGHT_GRAY_CONCRETE = get("minecraft:light_gray_concrete"); + @Nullable public static final BlockType LIGHT_GRAY_CONCRETE_POWDER = get("minecraft:light_gray_concrete_powder"); + @Nullable public static final BlockType LIGHT_GRAY_GLAZED_TERRACOTTA = get("minecraft:light_gray_glazed_terracotta"); + @Nullable public static final BlockType LIGHT_GRAY_SHULKER_BOX = get("minecraft:light_gray_shulker_box"); + @Nullable public static final BlockType LIGHT_GRAY_STAINED_GLASS = get("minecraft:light_gray_stained_glass"); + @Nullable public static final BlockType LIGHT_GRAY_STAINED_GLASS_PANE = get("minecraft:light_gray_stained_glass_pane"); + @Nullable public static final BlockType LIGHT_GRAY_TERRACOTTA = get("minecraft:light_gray_terracotta"); + @Nullable public static final BlockType LIGHT_GRAY_WALL_BANNER = get("minecraft:light_gray_wall_banner"); + @Nullable public static final BlockType LIGHT_GRAY_WOOL = get("minecraft:light_gray_wool"); + @Nullable public static final BlockType LIGHT_WEIGHTED_PRESSURE_PLATE = get("minecraft:light_weighted_pressure_plate"); + @Nullable public static final BlockType LIGHTNING_ROD = get("minecraft:lightning_rod"); + @Nullable public static final BlockType LILAC = get("minecraft:lilac"); + @Nullable public static final BlockType LILY_OF_THE_VALLEY = get("minecraft:lily_of_the_valley"); + @Nullable public static final BlockType LILY_PAD = get("minecraft:lily_pad"); + @Nullable public static final BlockType LIME_BANNER = get("minecraft:lime_banner"); + @Nullable public static final BlockType LIME_BED = get("minecraft:lime_bed"); + @Nullable public static final BlockType LIME_CANDLE = get("minecraft:lime_candle"); + @Nullable public static final BlockType LIME_CANDLE_CAKE = get("minecraft:lime_candle_cake"); + @Nullable public static final BlockType LIME_CARPET = get("minecraft:lime_carpet"); + @Nullable public static final BlockType LIME_CONCRETE = get("minecraft:lime_concrete"); + @Nullable public static final BlockType LIME_CONCRETE_POWDER = get("minecraft:lime_concrete_powder"); + @Nullable public static final BlockType LIME_GLAZED_TERRACOTTA = get("minecraft:lime_glazed_terracotta"); + @Nullable public static final BlockType LIME_SHULKER_BOX = get("minecraft:lime_shulker_box"); + @Nullable public static final BlockType LIME_STAINED_GLASS = get("minecraft:lime_stained_glass"); + @Nullable public static final BlockType LIME_STAINED_GLASS_PANE = get("minecraft:lime_stained_glass_pane"); + @Nullable public static final BlockType LIME_TERRACOTTA = get("minecraft:lime_terracotta"); + @Nullable public static final BlockType LIME_WALL_BANNER = get("minecraft:lime_wall_banner"); + @Nullable public static final BlockType LIME_WOOL = get("minecraft:lime_wool"); + @Nullable public static final BlockType LODESTONE = get("minecraft:lodestone"); + @Nullable public static final BlockType LOOM = get("minecraft:loom"); + @Nullable public static final BlockType MAGENTA_BANNER = get("minecraft:magenta_banner"); + @Nullable public static final BlockType MAGENTA_BED = get("minecraft:magenta_bed"); + @Nullable public static final BlockType MAGENTA_CANDLE = get("minecraft:magenta_candle"); + @Nullable public static final BlockType MAGENTA_CANDLE_CAKE = get("minecraft:magenta_candle_cake"); + @Nullable public static final BlockType MAGENTA_CARPET = get("minecraft:magenta_carpet"); + @Nullable public static final BlockType MAGENTA_CONCRETE = get("minecraft:magenta_concrete"); + @Nullable public static final BlockType MAGENTA_CONCRETE_POWDER = get("minecraft:magenta_concrete_powder"); + @Nullable public static final BlockType MAGENTA_GLAZED_TERRACOTTA = get("minecraft:magenta_glazed_terracotta"); + @Nullable public static final BlockType MAGENTA_SHULKER_BOX = get("minecraft:magenta_shulker_box"); + @Nullable public static final BlockType MAGENTA_STAINED_GLASS = get("minecraft:magenta_stained_glass"); + @Nullable public static final BlockType MAGENTA_STAINED_GLASS_PANE = get("minecraft:magenta_stained_glass_pane"); + @Nullable public static final BlockType MAGENTA_TERRACOTTA = get("minecraft:magenta_terracotta"); + @Nullable public static final BlockType MAGENTA_WALL_BANNER = get("minecraft:magenta_wall_banner"); + @Nullable public static final BlockType MAGENTA_WOOL = get("minecraft:magenta_wool"); + @Nullable public static final BlockType MAGMA_BLOCK = get("minecraft:magma_block"); + @Nullable public static final BlockType MANGROVE_BUTTON = get("minecraft:mangrove_button"); + @Nullable public static final BlockType MANGROVE_DOOR = get("minecraft:mangrove_door"); + @Nullable public static final BlockType MANGROVE_FENCE = get("minecraft:mangrove_fence"); + @Nullable public static final BlockType MANGROVE_FENCE_GATE = get("minecraft:mangrove_fence_gate"); + @Nullable public static final BlockType MANGROVE_HANGING_SIGN = get("minecraft:mangrove_hanging_sign"); + @Nullable public static final BlockType MANGROVE_LEAVES = get("minecraft:mangrove_leaves"); + @Nullable public static final BlockType MANGROVE_LOG = get("minecraft:mangrove_log"); + @Nullable public static final BlockType MANGROVE_PLANKS = get("minecraft:mangrove_planks"); + @Nullable public static final BlockType MANGROVE_PRESSURE_PLATE = get("minecraft:mangrove_pressure_plate"); + @Nullable public static final BlockType MANGROVE_PROPAGULE = get("minecraft:mangrove_propagule"); + @Nullable public static final BlockType MANGROVE_ROOTS = get("minecraft:mangrove_roots"); + @Nullable public static final BlockType MANGROVE_SIGN = get("minecraft:mangrove_sign"); + @Nullable public static final BlockType MANGROVE_SLAB = get("minecraft:mangrove_slab"); + @Nullable public static final BlockType MANGROVE_STAIRS = get("minecraft:mangrove_stairs"); + @Nullable public static final BlockType MANGROVE_TRAPDOOR = get("minecraft:mangrove_trapdoor"); + @Nullable public static final BlockType MANGROVE_WALL_HANGING_SIGN = get("minecraft:mangrove_wall_hanging_sign"); + @Nullable public static final BlockType MANGROVE_WALL_SIGN = get("minecraft:mangrove_wall_sign"); + @Nullable public static final BlockType MANGROVE_WOOD = get("minecraft:mangrove_wood"); + @Nullable public static final BlockType MEDIUM_AMETHYST_BUD = get("minecraft:medium_amethyst_bud"); + @Nullable public static final BlockType MELON = get("minecraft:melon"); + @Nullable public static final BlockType MELON_STEM = get("minecraft:melon_stem"); + @Nullable public static final BlockType MOSS_BLOCK = get("minecraft:moss_block"); + @Nullable public static final BlockType MOSS_CARPET = get("minecraft:moss_carpet"); + @Nullable public static final BlockType MOSSY_COBBLESTONE = get("minecraft:mossy_cobblestone"); + @Nullable public static final BlockType MOSSY_COBBLESTONE_SLAB = get("minecraft:mossy_cobblestone_slab"); + @Nullable public static final BlockType MOSSY_COBBLESTONE_STAIRS = get("minecraft:mossy_cobblestone_stairs"); + @Nullable public static final BlockType MOSSY_COBBLESTONE_WALL = get("minecraft:mossy_cobblestone_wall"); + @Nullable public static final BlockType MOSSY_STONE_BRICK_SLAB = get("minecraft:mossy_stone_brick_slab"); + @Nullable public static final BlockType MOSSY_STONE_BRICK_STAIRS = get("minecraft:mossy_stone_brick_stairs"); + @Nullable public static final BlockType MOSSY_STONE_BRICK_WALL = get("minecraft:mossy_stone_brick_wall"); + @Nullable public static final BlockType MOSSY_STONE_BRICKS = get("minecraft:mossy_stone_bricks"); + @Nullable public static final BlockType MOVING_PISTON = get("minecraft:moving_piston"); + @Nullable public static final BlockType MUD = get("minecraft:mud"); + @Nullable public static final BlockType MUD_BRICK_SLAB = get("minecraft:mud_brick_slab"); + @Nullable public static final BlockType MUD_BRICK_STAIRS = get("minecraft:mud_brick_stairs"); + @Nullable public static final BlockType MUD_BRICK_WALL = get("minecraft:mud_brick_wall"); + @Nullable public static final BlockType MUD_BRICKS = get("minecraft:mud_bricks"); + @Nullable public static final BlockType MUDDY_MANGROVE_ROOTS = get("minecraft:muddy_mangrove_roots"); + @Nullable public static final BlockType MUSHROOM_STEM = get("minecraft:mushroom_stem"); + @Nullable public static final BlockType MYCELIUM = get("minecraft:mycelium"); + @Nullable public static final BlockType NETHER_BRICK_FENCE = get("minecraft:nether_brick_fence"); + @Nullable public static final BlockType NETHER_BRICK_SLAB = get("minecraft:nether_brick_slab"); + @Nullable public static final BlockType NETHER_BRICK_STAIRS = get("minecraft:nether_brick_stairs"); + @Nullable public static final BlockType NETHER_BRICK_WALL = get("minecraft:nether_brick_wall"); + @Nullable public static final BlockType NETHER_BRICKS = get("minecraft:nether_bricks"); + @Nullable public static final BlockType NETHER_GOLD_ORE = get("minecraft:nether_gold_ore"); + @Nullable public static final BlockType NETHER_PORTAL = get("minecraft:nether_portal"); + @Nullable public static final BlockType NETHER_QUARTZ_ORE = get("minecraft:nether_quartz_ore"); + @Nullable public static final BlockType NETHER_SPROUTS = get("minecraft:nether_sprouts"); + @Nullable public static final BlockType NETHER_WART = get("minecraft:nether_wart"); + @Nullable public static final BlockType NETHER_WART_BLOCK = get("minecraft:nether_wart_block"); + @Nullable public static final BlockType NETHERITE_BLOCK = get("minecraft:netherite_block"); + @Nullable public static final BlockType NETHERRACK = get("minecraft:netherrack"); + @Nullable public static final BlockType NOTE_BLOCK = get("minecraft:note_block"); + @Nullable public static final BlockType OAK_BUTTON = get("minecraft:oak_button"); + @Nullable public static final BlockType OAK_DOOR = get("minecraft:oak_door"); + @Nullable public static final BlockType OAK_FENCE = get("minecraft:oak_fence"); + @Nullable public static final BlockType OAK_FENCE_GATE = get("minecraft:oak_fence_gate"); + @Nullable public static final BlockType OAK_HANGING_SIGN = get("minecraft:oak_hanging_sign"); + @Nullable public static final BlockType OAK_LEAVES = get("minecraft:oak_leaves"); + @Nullable public static final BlockType OAK_LOG = get("minecraft:oak_log"); + @Nullable public static final BlockType OAK_PLANKS = get("minecraft:oak_planks"); + @Nullable public static final BlockType OAK_PRESSURE_PLATE = get("minecraft:oak_pressure_plate"); + @Nullable public static final BlockType OAK_SAPLING = get("minecraft:oak_sapling"); + @Nullable public static final BlockType OAK_SIGN = get("minecraft:oak_sign"); + @Nullable public static final BlockType OAK_SLAB = get("minecraft:oak_slab"); + @Nullable public static final BlockType OAK_STAIRS = get("minecraft:oak_stairs"); + @Nullable public static final BlockType OAK_TRAPDOOR = get("minecraft:oak_trapdoor"); + @Nullable public static final BlockType OAK_WALL_HANGING_SIGN = get("minecraft:oak_wall_hanging_sign"); + @Nullable public static final BlockType OAK_WALL_SIGN = get("minecraft:oak_wall_sign"); + @Nullable public static final BlockType OAK_WOOD = get("minecraft:oak_wood"); + @Nullable public static final BlockType OBSERVER = get("minecraft:observer"); + @Nullable public static final BlockType OBSIDIAN = get("minecraft:obsidian"); + @Nullable public static final BlockType OCHRE_FROGLIGHT = get("minecraft:ochre_froglight"); + @Nullable public static final BlockType ORANGE_BANNER = get("minecraft:orange_banner"); + @Nullable public static final BlockType ORANGE_BED = get("minecraft:orange_bed"); + @Nullable public static final BlockType ORANGE_CANDLE = get("minecraft:orange_candle"); + @Nullable public static final BlockType ORANGE_CANDLE_CAKE = get("minecraft:orange_candle_cake"); + @Nullable public static final BlockType ORANGE_CARPET = get("minecraft:orange_carpet"); + @Nullable public static final BlockType ORANGE_CONCRETE = get("minecraft:orange_concrete"); + @Nullable public static final BlockType ORANGE_CONCRETE_POWDER = get("minecraft:orange_concrete_powder"); + @Nullable public static final BlockType ORANGE_GLAZED_TERRACOTTA = get("minecraft:orange_glazed_terracotta"); + @Nullable public static final BlockType ORANGE_SHULKER_BOX = get("minecraft:orange_shulker_box"); + @Nullable public static final BlockType ORANGE_STAINED_GLASS = get("minecraft:orange_stained_glass"); + @Nullable public static final BlockType ORANGE_STAINED_GLASS_PANE = get("minecraft:orange_stained_glass_pane"); + @Nullable public static final BlockType ORANGE_TERRACOTTA = get("minecraft:orange_terracotta"); + @Nullable public static final BlockType ORANGE_TULIP = get("minecraft:orange_tulip"); + @Nullable public static final BlockType ORANGE_WALL_BANNER = get("minecraft:orange_wall_banner"); + @Nullable public static final BlockType ORANGE_WOOL = get("minecraft:orange_wool"); + @Nullable public static final BlockType OXEYE_DAISY = get("minecraft:oxeye_daisy"); + @Nullable public static final BlockType OXIDIZED_COPPER = get("minecraft:oxidized_copper"); + @Nullable public static final BlockType OXIDIZED_CUT_COPPER = get("minecraft:oxidized_cut_copper"); + @Nullable public static final BlockType OXIDIZED_CUT_COPPER_SLAB = get("minecraft:oxidized_cut_copper_slab"); + @Nullable public static final BlockType OXIDIZED_CUT_COPPER_STAIRS = get("minecraft:oxidized_cut_copper_stairs"); + @Nullable public static final BlockType PACKED_ICE = get("minecraft:packed_ice"); + @Nullable public static final BlockType PACKED_MUD = get("minecraft:packed_mud"); + @Nullable public static final BlockType PEARLESCENT_FROGLIGHT = get("minecraft:pearlescent_froglight"); + @Nullable public static final BlockType PEONY = get("minecraft:peony"); + @Nullable public static final BlockType PETRIFIED_OAK_SLAB = get("minecraft:petrified_oak_slab"); + @Nullable public static final BlockType PIGLIN_HEAD = get("minecraft:piglin_head"); + @Nullable public static final BlockType PIGLIN_WALL_HEAD = get("minecraft:piglin_wall_head"); + @Nullable public static final BlockType PINK_BANNER = get("minecraft:pink_banner"); + @Nullable public static final BlockType PINK_BED = get("minecraft:pink_bed"); + @Nullable public static final BlockType PINK_CANDLE = get("minecraft:pink_candle"); + @Nullable public static final BlockType PINK_CANDLE_CAKE = get("minecraft:pink_candle_cake"); + @Nullable public static final BlockType PINK_CARPET = get("minecraft:pink_carpet"); + @Nullable public static final BlockType PINK_CONCRETE = get("minecraft:pink_concrete"); + @Nullable public static final BlockType PINK_CONCRETE_POWDER = get("minecraft:pink_concrete_powder"); + @Nullable public static final BlockType PINK_GLAZED_TERRACOTTA = get("minecraft:pink_glazed_terracotta"); + @Nullable public static final BlockType PINK_PETALS = get("minecraft:pink_petals"); + @Nullable public static final BlockType PINK_SHULKER_BOX = get("minecraft:pink_shulker_box"); + @Nullable public static final BlockType PINK_STAINED_GLASS = get("minecraft:pink_stained_glass"); + @Nullable public static final BlockType PINK_STAINED_GLASS_PANE = get("minecraft:pink_stained_glass_pane"); + @Nullable public static final BlockType PINK_TERRACOTTA = get("minecraft:pink_terracotta"); + @Nullable public static final BlockType PINK_TULIP = get("minecraft:pink_tulip"); + @Nullable public static final BlockType PINK_WALL_BANNER = get("minecraft:pink_wall_banner"); + @Nullable public static final BlockType PINK_WOOL = get("minecraft:pink_wool"); + @Nullable public static final BlockType PISTON = get("minecraft:piston"); + @Nullable public static final BlockType PISTON_HEAD = get("minecraft:piston_head"); + @Nullable public static final BlockType PITCHER_CROP = get("minecraft:pitcher_crop"); + @Nullable public static final BlockType PITCHER_PLANT = get("minecraft:pitcher_plant"); + @Nullable public static final BlockType PLAYER_HEAD = get("minecraft:player_head"); + @Nullable public static final BlockType PLAYER_WALL_HEAD = get("minecraft:player_wall_head"); + @Nullable public static final BlockType PODZOL = get("minecraft:podzol"); + @Nullable public static final BlockType POINTED_DRIPSTONE = get("minecraft:pointed_dripstone"); + @Nullable public static final BlockType POLISHED_ANDESITE = get("minecraft:polished_andesite"); + @Nullable public static final BlockType POLISHED_ANDESITE_SLAB = get("minecraft:polished_andesite_slab"); + @Nullable public static final BlockType POLISHED_ANDESITE_STAIRS = get("minecraft:polished_andesite_stairs"); + @Nullable public static final BlockType POLISHED_BASALT = get("minecraft:polished_basalt"); + @Nullable public static final BlockType POLISHED_BLACKSTONE = get("minecraft:polished_blackstone"); + @Nullable public static final BlockType POLISHED_BLACKSTONE_BRICK_SLAB = get("minecraft:polished_blackstone_brick_slab"); + @Nullable public static final BlockType POLISHED_BLACKSTONE_BRICK_STAIRS = get("minecraft:polished_blackstone_brick_stairs"); + @Nullable public static final BlockType POLISHED_BLACKSTONE_BRICK_WALL = get("minecraft:polished_blackstone_brick_wall"); + @Nullable public static final BlockType POLISHED_BLACKSTONE_BRICKS = get("minecraft:polished_blackstone_bricks"); + @Nullable public static final BlockType POLISHED_BLACKSTONE_BUTTON = get("minecraft:polished_blackstone_button"); + @Nullable public static final BlockType POLISHED_BLACKSTONE_PRESSURE_PLATE = get("minecraft:polished_blackstone_pressure_plate"); + @Nullable public static final BlockType POLISHED_BLACKSTONE_SLAB = get("minecraft:polished_blackstone_slab"); + @Nullable public static final BlockType POLISHED_BLACKSTONE_STAIRS = get("minecraft:polished_blackstone_stairs"); + @Nullable public static final BlockType POLISHED_BLACKSTONE_WALL = get("minecraft:polished_blackstone_wall"); + @Nullable public static final BlockType POLISHED_DEEPSLATE = get("minecraft:polished_deepslate"); + @Nullable public static final BlockType POLISHED_DEEPSLATE_SLAB = get("minecraft:polished_deepslate_slab"); + @Nullable public static final BlockType POLISHED_DEEPSLATE_STAIRS = get("minecraft:polished_deepslate_stairs"); + @Nullable public static final BlockType POLISHED_DEEPSLATE_WALL = get("minecraft:polished_deepslate_wall"); + @Nullable public static final BlockType POLISHED_DIORITE = get("minecraft:polished_diorite"); + @Nullable public static final BlockType POLISHED_DIORITE_SLAB = get("minecraft:polished_diorite_slab"); + @Nullable public static final BlockType POLISHED_DIORITE_STAIRS = get("minecraft:polished_diorite_stairs"); + @Nullable public static final BlockType POLISHED_GRANITE = get("minecraft:polished_granite"); + @Nullable public static final BlockType POLISHED_GRANITE_SLAB = get("minecraft:polished_granite_slab"); + @Nullable public static final BlockType POLISHED_GRANITE_STAIRS = get("minecraft:polished_granite_stairs"); + @Nullable public static final BlockType POPPY = get("minecraft:poppy"); + @Nullable public static final BlockType POTATOES = get("minecraft:potatoes"); + @Nullable public static final BlockType POTTED_ACACIA_SAPLING = get("minecraft:potted_acacia_sapling"); + @Nullable public static final BlockType POTTED_ALLIUM = get("minecraft:potted_allium"); + @Nullable public static final BlockType POTTED_AZALEA_BUSH = get("minecraft:potted_azalea_bush"); + @Nullable public static final BlockType POTTED_AZURE_BLUET = get("minecraft:potted_azure_bluet"); + @Nullable public static final BlockType POTTED_BAMBOO = get("minecraft:potted_bamboo"); + @Nullable public static final BlockType POTTED_BIRCH_SAPLING = get("minecraft:potted_birch_sapling"); + @Nullable public static final BlockType POTTED_BLUE_ORCHID = get("minecraft:potted_blue_orchid"); + @Nullable public static final BlockType POTTED_BROWN_MUSHROOM = get("minecraft:potted_brown_mushroom"); + @Nullable public static final BlockType POTTED_CACTUS = get("minecraft:potted_cactus"); + @Nullable public static final BlockType POTTED_CHERRY_SAPLING = get("minecraft:potted_cherry_sapling"); + @Nullable public static final BlockType POTTED_CORNFLOWER = get("minecraft:potted_cornflower"); + @Nullable public static final BlockType POTTED_CRIMSON_FUNGUS = get("minecraft:potted_crimson_fungus"); + @Nullable public static final BlockType POTTED_CRIMSON_ROOTS = get("minecraft:potted_crimson_roots"); + @Nullable public static final BlockType POTTED_DANDELION = get("minecraft:potted_dandelion"); + @Nullable public static final BlockType POTTED_DARK_OAK_SAPLING = get("minecraft:potted_dark_oak_sapling"); + @Nullable public static final BlockType POTTED_DEAD_BUSH = get("minecraft:potted_dead_bush"); + @Nullable public static final BlockType POTTED_FERN = get("minecraft:potted_fern"); + @Nullable public static final BlockType POTTED_FLOWERING_AZALEA_BUSH = get("minecraft:potted_flowering_azalea_bush"); + @Nullable public static final BlockType POTTED_JUNGLE_SAPLING = get("minecraft:potted_jungle_sapling"); + @Nullable public static final BlockType POTTED_LILY_OF_THE_VALLEY = get("minecraft:potted_lily_of_the_valley"); + @Nullable public static final BlockType POTTED_MANGROVE_PROPAGULE = get("minecraft:potted_mangrove_propagule"); + @Nullable public static final BlockType POTTED_OAK_SAPLING = get("minecraft:potted_oak_sapling"); + @Nullable public static final BlockType POTTED_ORANGE_TULIP = get("minecraft:potted_orange_tulip"); + @Nullable public static final BlockType POTTED_OXEYE_DAISY = get("minecraft:potted_oxeye_daisy"); + @Nullable public static final BlockType POTTED_PINK_TULIP = get("minecraft:potted_pink_tulip"); + @Nullable public static final BlockType POTTED_POPPY = get("minecraft:potted_poppy"); + @Nullable public static final BlockType POTTED_RED_MUSHROOM = get("minecraft:potted_red_mushroom"); + @Nullable public static final BlockType POTTED_RED_TULIP = get("minecraft:potted_red_tulip"); + @Nullable public static final BlockType POTTED_SPRUCE_SAPLING = get("minecraft:potted_spruce_sapling"); + @Nullable public static final BlockType POTTED_TORCHFLOWER = get("minecraft:potted_torchflower"); + @Nullable public static final BlockType POTTED_WARPED_FUNGUS = get("minecraft:potted_warped_fungus"); + @Nullable public static final BlockType POTTED_WARPED_ROOTS = get("minecraft:potted_warped_roots"); + @Nullable public static final BlockType POTTED_WHITE_TULIP = get("minecraft:potted_white_tulip"); + @Nullable public static final BlockType POTTED_WITHER_ROSE = get("minecraft:potted_wither_rose"); + @Nullable public static final BlockType POWDER_SNOW = get("minecraft:powder_snow"); + @Nullable public static final BlockType POWDER_SNOW_CAULDRON = get("minecraft:powder_snow_cauldron"); + @Nullable public static final BlockType POWERED_RAIL = get("minecraft:powered_rail"); + @Nullable public static final BlockType PRISMARINE = get("minecraft:prismarine"); + @Nullable public static final BlockType PRISMARINE_BRICK_SLAB = get("minecraft:prismarine_brick_slab"); + @Nullable public static final BlockType PRISMARINE_BRICK_STAIRS = get("minecraft:prismarine_brick_stairs"); + @Nullable public static final BlockType PRISMARINE_BRICKS = get("minecraft:prismarine_bricks"); + @Nullable public static final BlockType PRISMARINE_SLAB = get("minecraft:prismarine_slab"); + @Nullable public static final BlockType PRISMARINE_STAIRS = get("minecraft:prismarine_stairs"); + @Nullable public static final BlockType PRISMARINE_WALL = get("minecraft:prismarine_wall"); + @Nullable public static final BlockType PUMPKIN = get("minecraft:pumpkin"); + @Nullable public static final BlockType PUMPKIN_STEM = get("minecraft:pumpkin_stem"); + @Nullable public static final BlockType PURPLE_BANNER = get("minecraft:purple_banner"); + @Nullable public static final BlockType PURPLE_BED = get("minecraft:purple_bed"); + @Nullable public static final BlockType PURPLE_CANDLE = get("minecraft:purple_candle"); + @Nullable public static final BlockType PURPLE_CANDLE_CAKE = get("minecraft:purple_candle_cake"); + @Nullable public static final BlockType PURPLE_CARPET = get("minecraft:purple_carpet"); + @Nullable public static final BlockType PURPLE_CONCRETE = get("minecraft:purple_concrete"); + @Nullable public static final BlockType PURPLE_CONCRETE_POWDER = get("minecraft:purple_concrete_powder"); + @Nullable public static final BlockType PURPLE_GLAZED_TERRACOTTA = get("minecraft:purple_glazed_terracotta"); + @Nullable public static final BlockType PURPLE_SHULKER_BOX = get("minecraft:purple_shulker_box"); + @Nullable public static final BlockType PURPLE_STAINED_GLASS = get("minecraft:purple_stained_glass"); + @Nullable public static final BlockType PURPLE_STAINED_GLASS_PANE = get("minecraft:purple_stained_glass_pane"); + @Nullable public static final BlockType PURPLE_TERRACOTTA = get("minecraft:purple_terracotta"); + @Nullable public static final BlockType PURPLE_WALL_BANNER = get("minecraft:purple_wall_banner"); + @Nullable public static final BlockType PURPLE_WOOL = get("minecraft:purple_wool"); + @Nullable public static final BlockType PURPUR_BLOCK = get("minecraft:purpur_block"); + @Nullable public static final BlockType PURPUR_PILLAR = get("minecraft:purpur_pillar"); + @Nullable public static final BlockType PURPUR_SLAB = get("minecraft:purpur_slab"); + @Nullable public static final BlockType PURPUR_STAIRS = get("minecraft:purpur_stairs"); + @Nullable public static final BlockType QUARTZ_BLOCK = get("minecraft:quartz_block"); + @Nullable public static final BlockType QUARTZ_BRICKS = get("minecraft:quartz_bricks"); + @Nullable public static final BlockType QUARTZ_PILLAR = get("minecraft:quartz_pillar"); + @Nullable public static final BlockType QUARTZ_SLAB = get("minecraft:quartz_slab"); + @Nullable public static final BlockType QUARTZ_STAIRS = get("minecraft:quartz_stairs"); + @Nullable public static final BlockType RAIL = get("minecraft:rail"); + @Nullable public static final BlockType RAW_COPPER_BLOCK = get("minecraft:raw_copper_block"); + @Nullable public static final BlockType RAW_GOLD_BLOCK = get("minecraft:raw_gold_block"); + @Nullable public static final BlockType RAW_IRON_BLOCK = get("minecraft:raw_iron_block"); + @Nullable public static final BlockType RED_BANNER = get("minecraft:red_banner"); + @Nullable public static final BlockType RED_BED = get("minecraft:red_bed"); + @Nullable public static final BlockType RED_CANDLE = get("minecraft:red_candle"); + @Nullable public static final BlockType RED_CANDLE_CAKE = get("minecraft:red_candle_cake"); + @Nullable public static final BlockType RED_CARPET = get("minecraft:red_carpet"); + @Nullable public static final BlockType RED_CONCRETE = get("minecraft:red_concrete"); + @Nullable public static final BlockType RED_CONCRETE_POWDER = get("minecraft:red_concrete_powder"); + @Nullable public static final BlockType RED_GLAZED_TERRACOTTA = get("minecraft:red_glazed_terracotta"); + @Nullable public static final BlockType RED_MUSHROOM = get("minecraft:red_mushroom"); + @Nullable public static final BlockType RED_MUSHROOM_BLOCK = get("minecraft:red_mushroom_block"); + @Nullable public static final BlockType RED_NETHER_BRICK_SLAB = get("minecraft:red_nether_brick_slab"); + @Nullable public static final BlockType RED_NETHER_BRICK_STAIRS = get("minecraft:red_nether_brick_stairs"); + @Nullable public static final BlockType RED_NETHER_BRICK_WALL = get("minecraft:red_nether_brick_wall"); + @Nullable public static final BlockType RED_NETHER_BRICKS = get("minecraft:red_nether_bricks"); + @Nullable public static final BlockType RED_SAND = get("minecraft:red_sand"); + @Nullable public static final BlockType RED_SANDSTONE = get("minecraft:red_sandstone"); + @Nullable public static final BlockType RED_SANDSTONE_SLAB = get("minecraft:red_sandstone_slab"); + @Nullable public static final BlockType RED_SANDSTONE_STAIRS = get("minecraft:red_sandstone_stairs"); + @Nullable public static final BlockType RED_SANDSTONE_WALL = get("minecraft:red_sandstone_wall"); + @Nullable public static final BlockType RED_SHULKER_BOX = get("minecraft:red_shulker_box"); + @Nullable public static final BlockType RED_STAINED_GLASS = get("minecraft:red_stained_glass"); + @Nullable public static final BlockType RED_STAINED_GLASS_PANE = get("minecraft:red_stained_glass_pane"); + @Nullable public static final BlockType RED_TERRACOTTA = get("minecraft:red_terracotta"); + @Nullable public static final BlockType RED_TULIP = get("minecraft:red_tulip"); + @Nullable public static final BlockType RED_WALL_BANNER = get("minecraft:red_wall_banner"); + @Nullable public static final BlockType RED_WOOL = get("minecraft:red_wool"); + @Nullable public static final BlockType REDSTONE_BLOCK = get("minecraft:redstone_block"); + @Nullable public static final BlockType REDSTONE_LAMP = get("minecraft:redstone_lamp"); + @Nullable public static final BlockType REDSTONE_ORE = get("minecraft:redstone_ore"); + @Nullable public static final BlockType REDSTONE_TORCH = get("minecraft:redstone_torch"); + @Nullable public static final BlockType REDSTONE_WALL_TORCH = get("minecraft:redstone_wall_torch"); + @Nullable public static final BlockType REDSTONE_WIRE = get("minecraft:redstone_wire"); + @Nullable public static final BlockType REINFORCED_DEEPSLATE = get("minecraft:reinforced_deepslate"); + @Nullable public static final BlockType REPEATER = get("minecraft:repeater"); + @Nullable public static final BlockType REPEATING_COMMAND_BLOCK = get("minecraft:repeating_command_block"); + @Nullable public static final BlockType RESPAWN_ANCHOR = get("minecraft:respawn_anchor"); + @Nullable public static final BlockType ROOTED_DIRT = get("minecraft:rooted_dirt"); + @Nullable public static final BlockType ROSE_BUSH = get("minecraft:rose_bush"); + @Nullable public static final BlockType SAND = get("minecraft:sand"); + @Nullable public static final BlockType SANDSTONE = get("minecraft:sandstone"); + @Nullable public static final BlockType SANDSTONE_SLAB = get("minecraft:sandstone_slab"); + @Nullable public static final BlockType SANDSTONE_STAIRS = get("minecraft:sandstone_stairs"); + @Nullable public static final BlockType SANDSTONE_WALL = get("minecraft:sandstone_wall"); + @Nullable public static final BlockType SCAFFOLDING = get("minecraft:scaffolding"); + @Nullable public static final BlockType SCULK = get("minecraft:sculk"); + @Nullable public static final BlockType SCULK_CATALYST = get("minecraft:sculk_catalyst"); + @Nullable public static final BlockType SCULK_SENSOR = get("minecraft:sculk_sensor"); + @Nullable public static final BlockType SCULK_SHRIEKER = get("minecraft:sculk_shrieker"); + @Nullable public static final BlockType SCULK_VEIN = get("minecraft:sculk_vein"); + @Nullable public static final BlockType SEA_LANTERN = get("minecraft:sea_lantern"); + @Nullable public static final BlockType SEA_PICKLE = get("minecraft:sea_pickle"); + @Nullable public static final BlockType SEAGRASS = get("minecraft:seagrass"); + @Nullable public static final BlockType SHROOMLIGHT = get("minecraft:shroomlight"); + @Nullable public static final BlockType SHULKER_BOX = get("minecraft:shulker_box"); + @Deprecated @Nullable public static final BlockType SIGN = get("minecraft:sign"); + @Nullable public static final BlockType SKELETON_SKULL = get("minecraft:skeleton_skull"); + @Nullable public static final BlockType SKELETON_WALL_SKULL = get("minecraft:skeleton_wall_skull"); + @Nullable public static final BlockType SLIME_BLOCK = get("minecraft:slime_block"); + @Nullable public static final BlockType SMALL_AMETHYST_BUD = get("minecraft:small_amethyst_bud"); + @Nullable public static final BlockType SMALL_DRIPLEAF = get("minecraft:small_dripleaf"); + @Nullable public static final BlockType SMITHING_TABLE = get("minecraft:smithing_table"); + @Nullable public static final BlockType SMOKER = get("minecraft:smoker"); + @Nullable public static final BlockType SMOOTH_BASALT = get("minecraft:smooth_basalt"); + @Nullable public static final BlockType SMOOTH_QUARTZ = get("minecraft:smooth_quartz"); + @Nullable public static final BlockType SMOOTH_QUARTZ_SLAB = get("minecraft:smooth_quartz_slab"); + @Nullable public static final BlockType SMOOTH_QUARTZ_STAIRS = get("minecraft:smooth_quartz_stairs"); + @Nullable public static final BlockType SMOOTH_RED_SANDSTONE = get("minecraft:smooth_red_sandstone"); + @Nullable public static final BlockType SMOOTH_RED_SANDSTONE_SLAB = get("minecraft:smooth_red_sandstone_slab"); + @Nullable public static final BlockType SMOOTH_RED_SANDSTONE_STAIRS = get("minecraft:smooth_red_sandstone_stairs"); + @Nullable public static final BlockType SMOOTH_SANDSTONE = get("minecraft:smooth_sandstone"); + @Nullable public static final BlockType SMOOTH_SANDSTONE_SLAB = get("minecraft:smooth_sandstone_slab"); + @Nullable public static final BlockType SMOOTH_SANDSTONE_STAIRS = get("minecraft:smooth_sandstone_stairs"); + @Nullable public static final BlockType SMOOTH_STONE = get("minecraft:smooth_stone"); + @Nullable public static final BlockType SMOOTH_STONE_SLAB = get("minecraft:smooth_stone_slab"); + @Nullable public static final BlockType SNIFFER_EGG = get("minecraft:sniffer_egg"); + @Nullable public static final BlockType SNOW = get("minecraft:snow"); + @Nullable public static final BlockType SNOW_BLOCK = get("minecraft:snow_block"); + @Nullable public static final BlockType SOUL_CAMPFIRE = get("minecraft:soul_campfire"); + @Nullable public static final BlockType SOUL_FIRE = get("minecraft:soul_fire"); + @Nullable public static final BlockType SOUL_LANTERN = get("minecraft:soul_lantern"); + @Nullable public static final BlockType SOUL_SAND = get("minecraft:soul_sand"); + @Nullable public static final BlockType SOUL_SOIL = get("minecraft:soul_soil"); + @Nullable public static final BlockType SOUL_TORCH = get("minecraft:soul_torch"); + @Nullable public static final BlockType SOUL_WALL_TORCH = get("minecraft:soul_wall_torch"); + @Nullable public static final BlockType SPAWNER = get("minecraft:spawner"); + @Nullable public static final BlockType SPONGE = get("minecraft:sponge"); + @Nullable public static final BlockType SPORE_BLOSSOM = get("minecraft:spore_blossom"); + @Nullable public static final BlockType SPRUCE_BUTTON = get("minecraft:spruce_button"); + @Nullable public static final BlockType SPRUCE_DOOR = get("minecraft:spruce_door"); + @Nullable public static final BlockType SPRUCE_FENCE = get("minecraft:spruce_fence"); + @Nullable public static final BlockType SPRUCE_FENCE_GATE = get("minecraft:spruce_fence_gate"); + @Nullable public static final BlockType SPRUCE_HANGING_SIGN = get("minecraft:spruce_hanging_sign"); + @Nullable public static final BlockType SPRUCE_LEAVES = get("minecraft:spruce_leaves"); + @Nullable public static final BlockType SPRUCE_LOG = get("minecraft:spruce_log"); + @Nullable public static final BlockType SPRUCE_PLANKS = get("minecraft:spruce_planks"); + @Nullable public static final BlockType SPRUCE_PRESSURE_PLATE = get("minecraft:spruce_pressure_plate"); + @Nullable public static final BlockType SPRUCE_SAPLING = get("minecraft:spruce_sapling"); + @Nullable public static final BlockType SPRUCE_SIGN = get("minecraft:spruce_sign"); + @Nullable public static final BlockType SPRUCE_SLAB = get("minecraft:spruce_slab"); + @Nullable public static final BlockType SPRUCE_STAIRS = get("minecraft:spruce_stairs"); + @Nullable public static final BlockType SPRUCE_TRAPDOOR = get("minecraft:spruce_trapdoor"); + @Nullable public static final BlockType SPRUCE_WALL_HANGING_SIGN = get("minecraft:spruce_wall_hanging_sign"); + @Nullable public static final BlockType SPRUCE_WALL_SIGN = get("minecraft:spruce_wall_sign"); + @Nullable public static final BlockType SPRUCE_WOOD = get("minecraft:spruce_wood"); + @Nullable public static final BlockType STICKY_PISTON = get("minecraft:sticky_piston"); + @Nullable public static final BlockType STONE = get("minecraft:stone"); + @Nullable public static final BlockType STONE_BRICK_SLAB = get("minecraft:stone_brick_slab"); + @Nullable public static final BlockType STONE_BRICK_STAIRS = get("minecraft:stone_brick_stairs"); + @Nullable public static final BlockType STONE_BRICK_WALL = get("minecraft:stone_brick_wall"); + @Nullable public static final BlockType STONE_BRICKS = get("minecraft:stone_bricks"); + @Nullable public static final BlockType STONE_BUTTON = get("minecraft:stone_button"); + @Nullable public static final BlockType STONE_PRESSURE_PLATE = get("minecraft:stone_pressure_plate"); + @Nullable public static final BlockType STONE_SLAB = get("minecraft:stone_slab"); + @Nullable public static final BlockType STONE_STAIRS = get("minecraft:stone_stairs"); + @Nullable public static final BlockType STONECUTTER = get("minecraft:stonecutter"); + @Nullable public static final BlockType STRIPPED_ACACIA_LOG = get("minecraft:stripped_acacia_log"); + @Nullable public static final BlockType STRIPPED_ACACIA_WOOD = get("minecraft:stripped_acacia_wood"); + @Nullable public static final BlockType STRIPPED_BAMBOO_BLOCK = get("minecraft:stripped_bamboo_block"); + @Nullable public static final BlockType STRIPPED_BIRCH_LOG = get("minecraft:stripped_birch_log"); + @Nullable public static final BlockType STRIPPED_BIRCH_WOOD = get("minecraft:stripped_birch_wood"); + @Nullable public static final BlockType STRIPPED_CHERRY_LOG = get("minecraft:stripped_cherry_log"); + @Nullable public static final BlockType STRIPPED_CHERRY_WOOD = get("minecraft:stripped_cherry_wood"); + @Nullable public static final BlockType STRIPPED_CRIMSON_HYPHAE = get("minecraft:stripped_crimson_hyphae"); + @Nullable public static final BlockType STRIPPED_CRIMSON_STEM = get("minecraft:stripped_crimson_stem"); + @Nullable public static final BlockType STRIPPED_DARK_OAK_LOG = get("minecraft:stripped_dark_oak_log"); + @Nullable public static final BlockType STRIPPED_DARK_OAK_WOOD = get("minecraft:stripped_dark_oak_wood"); + @Nullable public static final BlockType STRIPPED_JUNGLE_LOG = get("minecraft:stripped_jungle_log"); + @Nullable public static final BlockType STRIPPED_JUNGLE_WOOD = get("minecraft:stripped_jungle_wood"); + @Nullable public static final BlockType STRIPPED_MANGROVE_LOG = get("minecraft:stripped_mangrove_log"); + @Nullable public static final BlockType STRIPPED_MANGROVE_WOOD = get("minecraft:stripped_mangrove_wood"); + @Nullable public static final BlockType STRIPPED_OAK_LOG = get("minecraft:stripped_oak_log"); + @Nullable public static final BlockType STRIPPED_OAK_WOOD = get("minecraft:stripped_oak_wood"); + @Nullable public static final BlockType STRIPPED_SPRUCE_LOG = get("minecraft:stripped_spruce_log"); + @Nullable public static final BlockType STRIPPED_SPRUCE_WOOD = get("minecraft:stripped_spruce_wood"); + @Nullable public static final BlockType STRIPPED_WARPED_HYPHAE = get("minecraft:stripped_warped_hyphae"); + @Nullable public static final BlockType STRIPPED_WARPED_STEM = get("minecraft:stripped_warped_stem"); + @Nullable public static final BlockType STRUCTURE_BLOCK = get("minecraft:structure_block"); + @Nullable public static final BlockType STRUCTURE_VOID = get("minecraft:structure_void"); + @Nullable public static final BlockType SUGAR_CANE = get("minecraft:sugar_cane"); + @Nullable public static final BlockType SUNFLOWER = get("minecraft:sunflower"); + @Nullable public static final BlockType SUSPICIOUS_GRAVEL = get("minecraft:suspicious_gravel"); + @Nullable public static final BlockType SUSPICIOUS_SAND = get("minecraft:suspicious_sand"); + @Nullable public static final BlockType SWEET_BERRY_BUSH = get("minecraft:sweet_berry_bush"); + @Nullable public static final BlockType TALL_GRASS = get("minecraft:tall_grass"); + @Nullable public static final BlockType TALL_SEAGRASS = get("minecraft:tall_seagrass"); + @Nullable public static final BlockType TARGET = get("minecraft:target"); + @Nullable public static final BlockType TERRACOTTA = get("minecraft:terracotta"); + @Nullable public static final BlockType TINTED_GLASS = get("minecraft:tinted_glass"); + @Nullable public static final BlockType TNT = get("minecraft:tnt"); + @Nullable public static final BlockType TORCH = get("minecraft:torch"); + @Nullable public static final BlockType TORCHFLOWER = get("minecraft:torchflower"); + @Nullable public static final BlockType TORCHFLOWER_CROP = get("minecraft:torchflower_crop"); + @Nullable public static final BlockType TRAPPED_CHEST = get("minecraft:trapped_chest"); + @Nullable public static final BlockType TRIPWIRE = get("minecraft:tripwire"); + @Nullable public static final BlockType TRIPWIRE_HOOK = get("minecraft:tripwire_hook"); + @Nullable public static final BlockType TUBE_CORAL = get("minecraft:tube_coral"); + @Nullable public static final BlockType TUBE_CORAL_BLOCK = get("minecraft:tube_coral_block"); + @Nullable public static final BlockType TUBE_CORAL_FAN = get("minecraft:tube_coral_fan"); + @Nullable public static final BlockType TUBE_CORAL_WALL_FAN = get("minecraft:tube_coral_wall_fan"); + @Nullable public static final BlockType TUFF = get("minecraft:tuff"); + @Nullable public static final BlockType TURTLE_EGG = get("minecraft:turtle_egg"); + @Nullable public static final BlockType TWISTING_VINES = get("minecraft:twisting_vines"); + @Nullable public static final BlockType TWISTING_VINES_PLANT = get("minecraft:twisting_vines_plant"); + @Nullable public static final BlockType VERDANT_FROGLIGHT = get("minecraft:verdant_froglight"); + @Nullable public static final BlockType VINE = get("minecraft:vine"); + @Nullable public static final BlockType VOID_AIR = get("minecraft:void_air"); + @Deprecated @Nullable public static final BlockType WALL_SIGN = get("minecraft:wall_sign"); + @Nullable public static final BlockType WALL_TORCH = get("minecraft:wall_torch"); + @Nullable public static final BlockType WARPED_BUTTON = get("minecraft:warped_button"); + @Nullable public static final BlockType WARPED_DOOR = get("minecraft:warped_door"); + @Nullable public static final BlockType WARPED_FENCE = get("minecraft:warped_fence"); + @Nullable public static final BlockType WARPED_FENCE_GATE = get("minecraft:warped_fence_gate"); + @Nullable public static final BlockType WARPED_FUNGUS = get("minecraft:warped_fungus"); + @Nullable public static final BlockType WARPED_HANGING_SIGN = get("minecraft:warped_hanging_sign"); + @Nullable public static final BlockType WARPED_HYPHAE = get("minecraft:warped_hyphae"); + @Nullable public static final BlockType WARPED_NYLIUM = get("minecraft:warped_nylium"); + @Nullable public static final BlockType WARPED_PLANKS = get("minecraft:warped_planks"); + @Nullable public static final BlockType WARPED_PRESSURE_PLATE = get("minecraft:warped_pressure_plate"); + @Nullable public static final BlockType WARPED_ROOTS = get("minecraft:warped_roots"); + @Nullable public static final BlockType WARPED_SIGN = get("minecraft:warped_sign"); + @Nullable public static final BlockType WARPED_SLAB = get("minecraft:warped_slab"); + @Nullable public static final BlockType WARPED_STAIRS = get("minecraft:warped_stairs"); + @Nullable public static final BlockType WARPED_STEM = get("minecraft:warped_stem"); + @Nullable public static final BlockType WARPED_TRAPDOOR = get("minecraft:warped_trapdoor"); + @Nullable public static final BlockType WARPED_WALL_HANGING_SIGN = get("minecraft:warped_wall_hanging_sign"); + @Nullable public static final BlockType WARPED_WALL_SIGN = get("minecraft:warped_wall_sign"); + @Nullable public static final BlockType WARPED_WART_BLOCK = get("minecraft:warped_wart_block"); + @Nullable public static final BlockType WATER = get("minecraft:water"); + @Nullable public static final BlockType WATER_CAULDRON = get("minecraft:water_cauldron"); + @Nullable public static final BlockType WAXED_COPPER_BLOCK = get("minecraft:waxed_copper_block"); + @Nullable public static final BlockType WAXED_CUT_COPPER = get("minecraft:waxed_cut_copper"); + @Nullable public static final BlockType WAXED_CUT_COPPER_SLAB = get("minecraft:waxed_cut_copper_slab"); + @Nullable public static final BlockType WAXED_CUT_COPPER_STAIRS = get("minecraft:waxed_cut_copper_stairs"); + @Nullable public static final BlockType WAXED_EXPOSED_COPPER = get("minecraft:waxed_exposed_copper"); + @Nullable public static final BlockType WAXED_EXPOSED_CUT_COPPER = get("minecraft:waxed_exposed_cut_copper"); + @Nullable public static final BlockType WAXED_EXPOSED_CUT_COPPER_SLAB = get("minecraft:waxed_exposed_cut_copper_slab"); + @Nullable public static final BlockType WAXED_EXPOSED_CUT_COPPER_STAIRS = get("minecraft:waxed_exposed_cut_copper_stairs"); + @Nullable public static final BlockType WAXED_OXIDIZED_COPPER = get("minecraft:waxed_oxidized_copper"); + @Nullable public static final BlockType WAXED_OXIDIZED_CUT_COPPER = get("minecraft:waxed_oxidized_cut_copper"); + @Nullable public static final BlockType WAXED_OXIDIZED_CUT_COPPER_SLAB = get("minecraft:waxed_oxidized_cut_copper_slab"); + @Nullable public static final BlockType WAXED_OXIDIZED_CUT_COPPER_STAIRS = get("minecraft:waxed_oxidized_cut_copper_stairs"); + @Nullable public static final BlockType WAXED_WEATHERED_COPPER = get("minecraft:waxed_weathered_copper"); + @Nullable public static final BlockType WAXED_WEATHERED_CUT_COPPER = get("minecraft:waxed_weathered_cut_copper"); + @Nullable public static final BlockType WAXED_WEATHERED_CUT_COPPER_SLAB = get("minecraft:waxed_weathered_cut_copper_slab"); + @Nullable public static final BlockType WAXED_WEATHERED_CUT_COPPER_STAIRS = get("minecraft:waxed_weathered_cut_copper_stairs"); + @Nullable public static final BlockType WEATHERED_COPPER = get("minecraft:weathered_copper"); + @Nullable public static final BlockType WEATHERED_CUT_COPPER = get("minecraft:weathered_cut_copper"); + @Nullable public static final BlockType WEATHERED_CUT_COPPER_SLAB = get("minecraft:weathered_cut_copper_slab"); + @Nullable public static final BlockType WEATHERED_CUT_COPPER_STAIRS = get("minecraft:weathered_cut_copper_stairs"); + @Nullable public static final BlockType WEEPING_VINES = get("minecraft:weeping_vines"); + @Nullable public static final BlockType WEEPING_VINES_PLANT = get("minecraft:weeping_vines_plant"); + @Nullable public static final BlockType WET_SPONGE = get("minecraft:wet_sponge"); + @Nullable public static final BlockType WHEAT = get("minecraft:wheat"); + @Nullable public static final BlockType WHITE_BANNER = get("minecraft:white_banner"); + @Nullable public static final BlockType WHITE_BED = get("minecraft:white_bed"); + @Nullable public static final BlockType WHITE_CANDLE = get("minecraft:white_candle"); + @Nullable public static final BlockType WHITE_CANDLE_CAKE = get("minecraft:white_candle_cake"); + @Nullable public static final BlockType WHITE_CARPET = get("minecraft:white_carpet"); + @Nullable public static final BlockType WHITE_CONCRETE = get("minecraft:white_concrete"); + @Nullable public static final BlockType WHITE_CONCRETE_POWDER = get("minecraft:white_concrete_powder"); + @Nullable public static final BlockType WHITE_GLAZED_TERRACOTTA = get("minecraft:white_glazed_terracotta"); + @Nullable public static final BlockType WHITE_SHULKER_BOX = get("minecraft:white_shulker_box"); + @Nullable public static final BlockType WHITE_STAINED_GLASS = get("minecraft:white_stained_glass"); + @Nullable public static final BlockType WHITE_STAINED_GLASS_PANE = get("minecraft:white_stained_glass_pane"); + @Nullable public static final BlockType WHITE_TERRACOTTA = get("minecraft:white_terracotta"); + @Nullable public static final BlockType WHITE_TULIP = get("minecraft:white_tulip"); + @Nullable public static final BlockType WHITE_WALL_BANNER = get("minecraft:white_wall_banner"); + @Nullable public static final BlockType WHITE_WOOL = get("minecraft:white_wool"); + @Nullable public static final BlockType WITHER_ROSE = get("minecraft:wither_rose"); + @Nullable public static final BlockType WITHER_SKELETON_SKULL = get("minecraft:wither_skeleton_skull"); + @Nullable public static final BlockType WITHER_SKELETON_WALL_SKULL = get("minecraft:wither_skeleton_wall_skull"); + @Nullable public static final BlockType YELLOW_BANNER = get("minecraft:yellow_banner"); + @Nullable public static final BlockType YELLOW_BED = get("minecraft:yellow_bed"); + @Nullable public static final BlockType YELLOW_CANDLE = get("minecraft:yellow_candle"); + @Nullable public static final BlockType YELLOW_CANDLE_CAKE = get("minecraft:yellow_candle_cake"); + @Nullable public static final BlockType YELLOW_CARPET = get("minecraft:yellow_carpet"); + @Nullable public static final BlockType YELLOW_CONCRETE = get("minecraft:yellow_concrete"); + @Nullable public static final BlockType YELLOW_CONCRETE_POWDER = get("minecraft:yellow_concrete_powder"); + @Nullable public static final BlockType YELLOW_GLAZED_TERRACOTTA = get("minecraft:yellow_glazed_terracotta"); + @Nullable public static final BlockType YELLOW_SHULKER_BOX = get("minecraft:yellow_shulker_box"); + @Nullable public static final BlockType YELLOW_STAINED_GLASS = get("minecraft:yellow_stained_glass"); + @Nullable public static final BlockType YELLOW_STAINED_GLASS_PANE = get("minecraft:yellow_stained_glass_pane"); + @Nullable public static final BlockType YELLOW_TERRACOTTA = get("minecraft:yellow_terracotta"); + @Nullable public static final BlockType YELLOW_WALL_BANNER = get("minecraft:yellow_wall_banner"); + @Nullable public static final BlockType YELLOW_WOOL = get("minecraft:yellow_wool"); + @Nullable public static final BlockType ZOMBIE_HEAD = get("minecraft:zombie_head"); + @Nullable public static final BlockType ZOMBIE_WALL_HEAD = get("minecraft:zombie_wall_head"); + + private BlockTypes() { + } + + /** + * Gets the {@link BlockType} associated with the given id. + */ + public static @Nullable BlockType get(String id) { + return BlockType.REGISTRY.get(id); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/block/FuzzyBlockState.java b/src/main/java/com/sk89q/worldedit/world/block/FuzzyBlockState.java new file mode 100644 index 0000000..f4082dc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/block/FuzzyBlockState.java @@ -0,0 +1,151 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.block; + +import com.sk89q.worldedit.registry.state.Property; + +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A Fuzzy BlockState. Used for partial matching. + * + *

+ * Immutable, construct with {@link Builder}. + *

+ */ +public class FuzzyBlockState extends BlockState { + + FuzzyBlockState(BlockType blockType) { + super(blockType); + } + + private FuzzyBlockState(BlockType blockType, Map, Object> values) { + this(blockType); + for (Map.Entry, Object> entry : values.entrySet()) { + setState(entry.getKey(), entry.getValue()); + } + } + + /** + * Gets a full BlockState from this fuzzy one, filling in + * properties with default values where necessary. + * + * @return The full BlockState + */ + public BlockState getFullState() { + BlockState state = getBlockType().getDefaultState(); + for (Map.Entry, Object> entry : getStates().entrySet()) { + @SuppressWarnings("unchecked") + Property objKey = (Property) entry.getKey(); + state = state.with(objKey, entry.getValue()); + } + return state; + } + + @Override + public BlockState toImmutableState() { + return getFullState(); + } + + /** + * Gets an instance of a builder. + * + * @return The builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for FuzzyBlockState. + */ + public static class Builder { + private BlockType type; + private final Map, Object> values = new HashMap<>(); + + /** + * The type of the Fuzzy BlockState. + * + * @param type The type + * @return The builder, for chaining + */ + public Builder type(BlockType type) { + checkNotNull(type); + this.type = type; + return this; + } + + /** + * The type of the Fuzzy BlockState. + * + * @param state The state + * @return The builder, for chaining + */ + public Builder type(BlockState state) { + checkNotNull(state); + this.type = state.getBlockType(); + return this; + } + + /** + * Adds a property to the fuzzy BlockState. + * + * @param property The property + * @param value The value + * @param The property type + * @return The builder, for chaining + */ + public Builder withProperty(Property property, V value) { + checkNotNull(property); + checkNotNull(value); + checkNotNull(type, "The type must be set before the properties!"); + type.getProperty(property.getName()); // Verify the property is valid for this type + values.put(property, value); + return this; + } + + /** + * Builds a FuzzyBlockState from this builder. + * + * @return The fuzzy BlockState + */ + public FuzzyBlockState build() { + checkNotNull(type); + if (values.isEmpty()) { + return type.getFuzzyMatcher(); + } + return new FuzzyBlockState(type, values); + } + + /** + * Resets the builder. + * + * @return The builder, for chaining + */ + public Builder reset() { + this.type = null; + this.values.clear(); + return this; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java b/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java new file mode 100644 index 0000000..dfa3a8d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java @@ -0,0 +1,265 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.chunk; + +import com.sk89q.jnbt.*; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.registry.LegacyMapper; +import com.sk89q.worldedit.world.storage.InvalidFormatException; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class AnvilChunk implements Chunk { + + private final CompoundTag rootTag; + private final byte[][] blocks; + private final byte[][] blocksAdd; + private final byte[][] data; + private final int rootX; + private final int rootZ; + + private Map> tileEntities; + + /** + * Construct the chunk with a compound tag. + * + * @param tag the tag to read + * @throws DataException on a data error + */ + public AnvilChunk(CompoundTag tag) throws DataException { + rootTag = tag; + + rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue(); + rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue(); + + blocks = new byte[16][16 * 16 * 16]; + blocksAdd = new byte[16][16 * 16 * 8]; + data = new byte[16][16 * 16 * 8]; + + List sections = NBTUtils.getChildTag(rootTag.getValue(), "Sections", ListTag.class).getValue(); + + for (Tag rawSectionTag : sections) { + if (!(rawSectionTag instanceof CompoundTag)) { + continue; + } + + CompoundTag sectionTag = (CompoundTag) rawSectionTag; + if (!sectionTag.getValue().containsKey("Y")) { + continue; // Empty section. + } + + int y = NBTUtils.getChildTag(sectionTag.getValue(), "Y", ByteTag.class).getValue(); + if (y < 0 || y >= 16) { + continue; + } + + blocks[y] = NBTUtils.getChildTag(sectionTag.getValue(), + "Blocks", ByteArrayTag.class).getValue(); + data[y] = NBTUtils.getChildTag(sectionTag.getValue(), "Data", + ByteArrayTag.class).getValue(); + + // 4096 ID block support + if (sectionTag.getValue().containsKey("Add")) { + blocksAdd[y] = NBTUtils.getChildTag(sectionTag.getValue(), + "Add", ByteArrayTag.class).getValue(); + } + } + + int sectionsize = 16 * 16 * 16; + for (byte[] block : blocks) { + if (block.length != sectionsize) { + throw new InvalidFormatException( + "Chunk blocks byte array expected " + "to be " + + sectionsize + " bytes; found " + + block.length); + } + } + + for (byte[] aData : data) { + if (aData.length != (sectionsize / 2)) { + throw new InvalidFormatException("Chunk block data byte array " + + "expected to be " + sectionsize + " bytes; found " + + aData.length); + } + } + } + + private int getBlockID(BlockVector3 position) throws DataException { + int x = position.getX() - rootX * 16; + int y = position.getY(); + int z = position.getZ() - rootZ * 16; + + int section = y >> 4; + if (section < 0 || section >= blocks.length) { + throw new DataException("Chunk does not contain position " + position); + } + + int yindex = y & 0x0F; + + int index = x + (z * 16 + (yindex * 16 * 16)); + + try { + int addId = 0; + + // The block ID is the combination of the Blocks byte array with the + // Add byte array. 'Blocks' stores the lowest 8 bits of a block's ID, and + // 'Add' stores the highest 4 bits of the ID. The first block is stored + // in the lowest nibble in the Add byte array. + if (index % 2 == 0) { + addId = (blocksAdd[section][index >> 1] & 0x0F) << 8; + } else { + addId = (blocksAdd[section][index >> 1] & 0xF0) << 4; + } + + return (blocks[section][index] & 0xFF) + addId; + } catch (IndexOutOfBoundsException e) { + throw new DataException("Chunk does not contain position " + position); + } + } + + private int getBlockData(BlockVector3 position) throws DataException { + int x = position.getX() - rootX * 16; + int y = position.getY(); + int z = position.getZ() - rootZ * 16; + + int section = y >> 4; + int yIndex = y & 0x0F; + + if (section < 0 || section >= blocks.length) { + throw new DataException("Chunk does not contain position " + position); + } + + int index = x + (z * 16 + (yIndex * 16 * 16)); + boolean shift = index % 2 == 0; + index /= 2; + + try { + if (!shift) { + return (data[section][index] & 0xF0) >> 4; + } else { + return data[section][index] & 0xF; + } + } catch (IndexOutOfBoundsException e) { + throw new DataException("Chunk does not contain position " + position); + } + } + + /** + * Used to load the tile entities. + */ + private void populateTileEntities() throws DataException { + List tags = NBTUtils.getChildTag(rootTag.getValue(), + "TileEntities", ListTag.class).getValue(); + + tileEntities = new HashMap<>(); + + for (Tag tag : tags) { + if (!(tag instanceof CompoundTag)) { + throw new InvalidFormatException("CompoundTag expected in TileEntities"); + } + + CompoundTag t = (CompoundTag) tag; + + int x = 0; + int y = 0; + int z = 0; + + Map values = new HashMap<>(); + + for (Map.Entry entry : t.getValue().entrySet()) { + switch (entry.getKey()) { + case "x": + if (entry.getValue() instanceof IntTag) { + x = ((IntTag) entry.getValue()).getValue(); + } + break; + case "y": + if (entry.getValue() instanceof IntTag) { + y = ((IntTag) entry.getValue()).getValue(); + } + break; + case "z": + if (entry.getValue() instanceof IntTag) { + z = ((IntTag) entry.getValue()).getValue(); + } + break; + default: + break; + } + + values.put(entry.getKey(), entry.getValue()); + } + + BlockVector3 vec = BlockVector3.at(x, y, z); + tileEntities.put(vec, values); + } + } + + /** + * Get the map of tags keyed to strings for a block's tile entity data. May + * return null if there is no tile entity data. Not public yet because + * what this function returns isn't ideal for usage. + * + * @param position the position + * @return the compound tag for that position, which may be null + * @throws DataException thrown if there is a data error + */ + @Nullable + private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { + if (tileEntities == null) { + populateTileEntities(); + } + + Map values = tileEntities.get(position); + if (values == null) { + return null; + } + + return new CompoundTag(values); + } + + @Override + public BaseBlock getBlock(BlockVector3 position) throws DataException { + int id = getBlockID(position); + int data = getBlockData(position); + + BlockState state = LegacyMapper.getInstance().getBlockFromLegacy(id, data); + if (state == null) { + WorldEdit.logger.warn("Unknown legacy block " + id + ":" + data + " found when loading legacy anvil chunk."); + return BlockTypes.AIR.getDefaultState().toBaseBlock(); + } + CompoundTag tileEntity = getBlockTileEntity(position); + + if (tileEntity != null) { + return state.toBaseBlock(tileEntity); + } + + return state.toBaseBlock(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java new file mode 100644 index 0000000..512649c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -0,0 +1,240 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.chunk; + +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.LongArrayTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.storage.InvalidFormatException; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * The chunk format for Minecraft 1.13 to 1.15 + */ +public class AnvilChunk13 implements Chunk { + + private final CompoundTag rootTag; + private final BlockState[][] blocks; + private final int rootX; + private final int rootZ; + + private Map> tileEntities; + + /** + * Construct the chunk with a compound tag. + * + * @param tag the tag to read + * @throws DataException on a data error + */ + public AnvilChunk13(CompoundTag tag) throws DataException { + rootTag = tag; + + rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue(); + rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue(); + + blocks = new BlockState[16][]; + + List sections = NBTUtils.getChildTag(rootTag.getValue(), "Sections", ListTag.class).getValue(); + + for (Tag rawSectionTag : sections) { + if (!(rawSectionTag instanceof CompoundTag)) { + continue; + } + + CompoundTag sectionTag = (CompoundTag) rawSectionTag; + if (!sectionTag.getValue().containsKey("Y")) { + continue; // Empty section. + } + + int y = NBTUtils.getChildTag(sectionTag.getValue(), "Y", ByteTag.class).getValue(); + if (y < 0 || y >= 16) { + continue; + } + + // parse palette + List paletteEntries = sectionTag.getList("Palette", CompoundTag.class); + int paletteSize = paletteEntries.size(); + if (paletteSize == 0) { + continue; + } + BlockState[] palette = new BlockState[paletteSize]; + for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { + CompoundTag paletteEntry = paletteEntries.get(paletteEntryId); + BlockType type = BlockTypes.get(paletteEntry.getString("Name")); + if (type == null) { + throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name")); + } + BlockState blockState = type.getDefaultState(); + if (paletteEntry.containsKey("Properties")) { + CompoundTag properties = NBTUtils.getChildTag(paletteEntry.getValue(), "Properties", CompoundTag.class); + for (Property property : blockState.getStates().keySet()) { + if (properties.containsKey(property.getName())) { + String value = properties.getString(property.getName()); + try { + blockState = getBlockStateWith(blockState, property, value); + } catch (IllegalArgumentException e) { + throw new InvalidFormatException("Invalid block state for " + blockState.getBlockType().getId() + ", " + property.getName() + ": " + value); + } + } + } + } + palette[paletteEntryId] = blockState; + } + + // parse block states + long[] blockStatesSerialized = NBTUtils.getChildTag(sectionTag.getValue(), "BlockStates", LongArrayTag.class).getValue(); + + BlockState[] chunkSectionBlocks = new BlockState[16 * 16 * 16]; + blocks[y] = chunkSectionBlocks; + + readBlockStates(palette, blockStatesSerialized, chunkSectionBlocks); + } + } + + protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException { + int paletteBits = 4; + while ((1 << paletteBits) < palette.length) { + ++paletteBits; + } + int paletteMask = (1 << paletteBits) - 1; + + long currentSerializedValue = 0; + int nextSerializedItem = 0; + int remainingBits = 0; + for (int blockPos = 0; blockPos < chunkSectionBlocks.length; blockPos++) { + int localBlockId; + if (remainingBits < paletteBits) { + int bitsNextLong = paletteBits - remainingBits; + localBlockId = (int) currentSerializedValue; + if (nextSerializedItem >= blockStatesSerialized.length) { + throw new InvalidFormatException("Too short block state table"); + } + currentSerializedValue = blockStatesSerialized[nextSerializedItem++]; + localBlockId |= (currentSerializedValue & ((1 << bitsNextLong) - 1)) << remainingBits; + currentSerializedValue >>>= bitsNextLong; + remainingBits = 64 - bitsNextLong; + } else { + localBlockId = (int) (currentSerializedValue & paletteMask); + currentSerializedValue >>>= paletteBits; + remainingBits -= paletteBits; + } + if (localBlockId >= palette.length) { + throw new InvalidFormatException("Invalid block state table entry: " + localBlockId); + } + chunkSectionBlocks[blockPos] = palette[localBlockId]; + } + } + + private BlockState getBlockStateWith(BlockState source, Property property, String value) { + return source.with(property, property.getValueFor(value)); + } + + /** + * Used to load the tile entities. + */ + private void populateTileEntities() throws DataException { + tileEntities = new HashMap<>(); + if (!rootTag.getValue().containsKey("TileEntities")) { + return; + } + List tags = NBTUtils.getChildTag(rootTag.getValue(), + "TileEntities", ListTag.class).getValue(); + + for (Tag tag : tags) { + if (!(tag instanceof CompoundTag)) { + throw new InvalidFormatException("CompoundTag expected in TileEntities"); + } + + CompoundTag t = (CompoundTag) tag; + + Map values = new HashMap<>(t.getValue()); + int x = ((IntTag) values.get("x")).getValue(); + int y = ((IntTag) values.get("y")).getValue(); + int z = ((IntTag) values.get("z")).getValue(); + + BlockVector3 vec = BlockVector3.at(x, y, z); + tileEntities.put(vec, values); + } + } + + /** + * Get the map of tags keyed to strings for a block's tile entity data. May + * return null if there is no tile entity data. Not public yet because + * what this function returns isn't ideal for usage. + * + * @param position the position + * @return the compound tag for that position, which may be null + * @throws DataException thrown if there is a data error + */ + @Nullable + private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { + if (tileEntities == null) { + populateTileEntities(); + } + + Map values = tileEntities.get(position); + if (values == null) { + return null; + } + + return new CompoundTag(values); + } + + @Override + public BaseBlock getBlock(BlockVector3 position) throws DataException { + int x = position.getX() - rootX * 16; + int y = position.getY(); + int z = position.getZ() - rootZ * 16; + + int section = y >> 4; + int yIndex = y & 0x0F; + + if (section < 0 || section >= blocks.length) { + throw new DataException("Chunk does not contain position " + position); + } + + BlockState[] sectionBlocks = blocks[section]; + BlockState state = sectionBlocks != null ? sectionBlocks[(yIndex << 8) | (z << 4) | x] : BlockTypes.AIR.getDefaultState(); + + CompoundTag tileEntity = getBlockTileEntity(position); + + if (tileEntity != null) { + return state.toBaseBlock(tileEntity); + } + + return state.toBaseBlock(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java b/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java new file mode 100644 index 0000000..e7bfbd2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.chunk; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.storage.InvalidFormatException; + +/** + * The chunk format for Minecraft 1.16 and 1.17 + */ +public class AnvilChunk16 extends AnvilChunk13 { + + /** + * Construct the chunk with a compound tag. + * + * @param tag the tag to read + * @throws DataException on a data error + */ + public AnvilChunk16(CompoundTag tag) throws DataException { + super(tag); + } + + @Override + protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException { + PackedIntArrayReader reader = new PackedIntArrayReader(blockStatesSerialized); + for (int blockPos = 0; blockPos < chunkSectionBlocks.length; blockPos++) { + int index = reader.get(blockPos); + if (index >= palette.length) { + throw new InvalidFormatException("Invalid block state table entry: " + index); + } + chunkSectionBlocks[blockPos] = palette[index]; + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java b/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java new file mode 100644 index 0000000..e71c730 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java @@ -0,0 +1,222 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.chunk; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.LongArrayTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.storage.InvalidFormatException; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * The chunk format for Minecraft 1.18 and newer + */ +public class AnvilChunk18 implements Chunk { + + private final CompoundTag rootTag; + private final Int2ObjectOpenHashMap blocks; + private final int rootX; + private final int rootZ; + + private Map> tileEntities; + + /** + * Construct the chunk with a compound tag. + * + * @param tag the tag to read + * @throws DataException on a data error + */ + public AnvilChunk18(CompoundTag tag) throws DataException { + rootTag = tag; + + rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue(); + rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue(); + + List sections = NBTUtils.getChildTag(rootTag.getValue(), "sections", ListTag.class).getValue(); + blocks = new Int2ObjectOpenHashMap<>(sections.size()); + + for (Tag rawSectionTag : sections) { + if (!(rawSectionTag instanceof CompoundTag)) { + continue; + } + + CompoundTag sectionTag = (CompoundTag) rawSectionTag; + Object yValue = sectionTag.getValue().get("Y").getValue(); // sometimes a byte, sometimes an int + if (!(yValue instanceof Number)) { + throw new InvalidFormatException("Y is not numeric: " + yValue); + } + int y = ((Number) yValue).intValue(); + + Tag rawBlockStatesTag = sectionTag.getValue().get("block_states"); // null for sections outside of the world limits + if (rawBlockStatesTag instanceof CompoundTag) { + CompoundTag blockStatesTag = (CompoundTag) rawBlockStatesTag; + + // parse palette + List paletteEntries = blockStatesTag.getList("palette", CompoundTag.class); + int paletteSize = paletteEntries.size(); + if (paletteSize == 0) { + continue; + } + BlockState[] palette = new BlockState[paletteSize]; + for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { + CompoundTag paletteEntry = paletteEntries.get(paletteEntryId); + BlockType type = BlockTypes.get(paletteEntry.getString("Name")); + if (type == null) { + throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name")); + } + BlockState blockState = type.getDefaultState(); + if (paletteEntry.containsKey("Properties")) { + CompoundTag properties = NBTUtils.getChildTag(paletteEntry.getValue(), "Properties", CompoundTag.class); + for (Property property : blockState.getStates().keySet()) { + if (properties.containsKey(property.getName())) { + String value = properties.getString(property.getName()); + try { + blockState = getBlockStateWith(blockState, property, value); + } catch (IllegalArgumentException e) { + throw new InvalidFormatException("Invalid block state for " + blockState.getBlockType().getId() + ", " + property.getName() + ": " + value); + } + } + } + } + palette[paletteEntryId] = blockState; + } + if (paletteSize == 1) { + // the same block everywhere + blocks.put(y, palette); + continue; + } + + // parse block states + long[] blockStatesSerialized = NBTUtils.getChildTag(blockStatesTag.getValue(), "data", LongArrayTag.class).getValue(); + + BlockState[] chunkSectionBlocks = new BlockState[16 * 16 * 16]; + blocks.put(y, chunkSectionBlocks); + + readBlockStates(palette, blockStatesSerialized, chunkSectionBlocks); + } + } + } + + protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException { + PackedIntArrayReader reader = new PackedIntArrayReader(blockStatesSerialized); + for (int blockPos = 0; blockPos < chunkSectionBlocks.length; blockPos++) { + int index = reader.get(blockPos); + if (index >= palette.length) { + throw new InvalidFormatException("Invalid block state table entry: " + index); + } + chunkSectionBlocks[blockPos] = palette[index]; + } + } + + private BlockState getBlockStateWith(BlockState source, Property property, String value) { + return source.with(property, property.getValueFor(value)); + } + + /** + * Used to load the tile entities. + */ + private void populateTileEntities() throws DataException { + tileEntities = new HashMap<>(); + if (!rootTag.getValue().containsKey("block_entities")) { + return; + } + List tags = NBTUtils.getChildTag(rootTag.getValue(), + "block_entities", ListTag.class).getValue(); + + for (Tag tag : tags) { + if (!(tag instanceof CompoundTag)) { + throw new InvalidFormatException("CompoundTag expected in block_entities"); + } + + CompoundTag t = (CompoundTag) tag; + + Map values = new HashMap<>(t.getValue()); + int x = ((IntTag) values.get("x")).getValue(); + int y = ((IntTag) values.get("y")).getValue(); + int z = ((IntTag) values.get("z")).getValue(); + + BlockVector3 vec = BlockVector3.at(x, y, z); + tileEntities.put(vec, values); + } + } + + /** + * Get the map of tags keyed to strings for a block's tile entity data. May + * return null if there is no tile entity data. Not public yet because + * what this function returns isn't ideal for usage. + * + * @param position the position + * @return the compound tag for that position, which may be null + * @throws DataException thrown if there is a data error + */ + @Nullable + private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { + if (tileEntities == null) { + populateTileEntities(); + } + + Map values = tileEntities.get(position); + if (values == null) { + return null; + } + + return new CompoundTag(values); + } + + @Override + public BaseBlock getBlock(BlockVector3 position) throws DataException { + int x = position.getX() - rootX * 16; + int y = position.getY(); + int z = position.getZ() - rootZ * 16; + + int section = y >> 4; + int yIndex = y & 0x0F; + + BlockState[] sectionBlocks = blocks.get(section); + if (sectionBlocks == null) { + return BlockTypes.AIR.getDefaultState().toBaseBlock(); + } + BlockState state = sectionBlocks[sectionBlocks.length == 1 ? 0 : ((yIndex << 8) | (z << 4) | x)]; + + CompoundTag tileEntity = getBlockTileEntity(position); + + if (tileEntity != null) { + return state.toBaseBlock(tileEntity); + } + + return state.toBaseBlock(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/chunk/Chunk.java b/src/main/java/com/sk89q/worldedit/world/chunk/Chunk.java new file mode 100644 index 0000000..d33edf1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/chunk/Chunk.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.chunk; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.block.BaseBlock; + +/** + * A 16 by 16 block chunk. + */ +public interface Chunk { + + /** + * Get a block. + * + * @param position the position of the block + * @return block the block + * @throws DataException thrown on data error + */ + BaseBlock getBlock(BlockVector3 position) throws DataException; + +} diff --git a/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java b/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java new file mode 100644 index 0000000..8f5665c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java @@ -0,0 +1,201 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.chunk; + +import com.sk89q.jnbt.ByteArrayTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.registry.LegacyMapper; +import com.sk89q.worldedit.world.storage.InvalidFormatException; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents an Alpha chunk. + */ +public class OldChunk implements Chunk { + + private final CompoundTag rootTag; + private final byte[] blocks; + private final byte[] data; + private final int rootX; + private final int rootZ; + + private Map> tileEntities; + + /** + * Construct the chunk with a compound tag. + * + * @param tag the tag + * @throws DataException if there is an error getting the chunk data + */ + public OldChunk(CompoundTag tag) throws DataException { + rootTag = tag; + + blocks = NBTUtils.getChildTag(rootTag.getValue(), "Blocks", ByteArrayTag.class).getValue(); + data = NBTUtils.getChildTag(rootTag.getValue(), "Data", ByteArrayTag.class).getValue(); + rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue(); + rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue(); + + int size = 16 * 16 * 128; + if (blocks.length != size) { + throw new InvalidFormatException("Chunk blocks byte array expected " + + "to be " + size + " bytes; found " + blocks.length); + } + + if (data.length != (size / 2)) { + throw new InvalidFormatException("Chunk block data byte array " + + "expected to be " + size + " bytes; found " + data.length); + } + } + + /** + * Used to load the tile entities. + * + * @throws DataException if there is an error getting the chunk data + */ + private void populateTileEntities() throws DataException { + List tags = NBTUtils.getChildTag( + rootTag.getValue(), "TileEntities", ListTag.class) + .getValue(); + + tileEntities = new HashMap<>(); + + for (Tag tag : tags) { + if (!(tag instanceof CompoundTag)) { + throw new InvalidFormatException("CompoundTag expected in TileEntities"); + } + + CompoundTag t = (CompoundTag) tag; + + int x = 0; + int y = 0; + int z = 0; + + Map values = new HashMap<>(); + + for (Map.Entry entry : t.getValue().entrySet()) { + switch (entry.getKey()) { + case "x": + if (entry.getValue() instanceof IntTag) { + x = ((IntTag) entry.getValue()).getValue(); + } + break; + case "y": + if (entry.getValue() instanceof IntTag) { + y = ((IntTag) entry.getValue()).getValue(); + } + break; + case "z": + if (entry.getValue() instanceof IntTag) { + z = ((IntTag) entry.getValue()).getValue(); + } + break; + default: + break; + } + + values.put(entry.getKey(), entry.getValue()); + } + + BlockVector3 vec = BlockVector3.at(x, y, z); + tileEntities.put(vec, values); + } + } + + /** + * Get the map of tags keyed to strings for a block's tile entity data. May + * return null if there is no tile entity data. Not public yet because + * what this function returns isn't ideal for usage. + * + * @param position the position + * @return a tag + * @throws DataException if there is an error getting the chunk data + */ + private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { + if (tileEntities == null) { + populateTileEntities(); + } + + Map values = tileEntities.get(position); + if (values == null) { + return null; + } + return new CompoundTag(values); + } + + @Override + public BaseBlock getBlock(BlockVector3 position) throws DataException { + if (position.getY() >= 128) { + return BlockTypes.VOID_AIR.getDefaultState().toBaseBlock(); + } + int id; + int dataVal; + + int x = position.getX() - rootX * 16; + int y = position.getY(); + int z = position.getZ() - rootZ * 16; + int index = y + (z * 128 + (x * 128 * 16)); + try { + id = blocks[index]; + } catch (IndexOutOfBoundsException e) { + throw new DataException("Chunk does not contain position " + position); + } + + boolean shift = index % 2 == 0; + index /= 2; + + try { + if (!shift) { + dataVal = (data[index] & 0xF0) >> 4; + } else { + dataVal = data[index] & 0xF; + } + } catch (IndexOutOfBoundsException e) { + throw new DataException("Chunk does not contain position " + position); + } + + BlockState state = LegacyMapper.getInstance().getBlockFromLegacy(id, dataVal); + if (state == null) { + WorldEdit.logger.warn("Unknown legacy block " + id + ":" + dataVal + " found when loading legacy anvil chunk."); + return BlockTypes.AIR.getDefaultState().toBaseBlock(); + } + + CompoundTag tileEntity = getBlockTileEntity(position); + + if (tileEntity != null) { + return state.toBaseBlock(tileEntity); + } + + return state.toBaseBlock(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/chunk/PackedIntArrayReader.java b/src/main/java/com/sk89q/worldedit/world/chunk/PackedIntArrayReader.java new file mode 100644 index 0000000..a58d1f3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/chunk/PackedIntArrayReader.java @@ -0,0 +1,66 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.chunk; + +import static com.google.common.base.Preconditions.checkElementIndex; + +public class PackedIntArrayReader { + private static final int[] FACTORS = new int[64]; + + static { + FACTORS[0] = -1; + for (int i = 2; i <= 64; i++) { + FACTORS[i - 1] = (int) (Integer.toUnsignedLong(-1) / i); + } + } + + private static final int SIZE = 4096; + + private final long[] data; + private final int elementBits; + private final long maxValue; + private final int elementsPerLong; + private final int factor; + + public PackedIntArrayReader(long[] data) { + this.data = data; + this.elementBits = data.length * 64 / 4096; + this.maxValue = (1L << elementBits) - 1L; + this.elementsPerLong = 64 / elementBits; + this.factor = FACTORS[elementsPerLong - 1]; + int j = (SIZE + this.elementsPerLong - 1) / this.elementsPerLong; + if (j != data.length) { + throw new IllegalStateException("Invalid packed-int array provided, should be of length " + j); + } + } + + public int get(int index) { + checkElementIndex(index, SIZE); + int i = this.adjustIndex(index); + long l = this.data[i]; + int j = (index - i * this.elementsPerLong) * this.elementBits; + return (int) (l >> j & this.maxValue); + } + + private int adjustIndex(int i) { + return (int) ((long) i * factor + factor >> 32); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java b/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java new file mode 100644 index 0000000..f1761de --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.entity; + +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; + +public class EntityType implements Keyed { + + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("entity type", true); + + private final String id; + + public EntityType(String id) { + // If it has no namespace, assume minecraft. + if (!id.contains(":")) { + id = "minecraft:" + id; + } + this.id = id; + } + + @Override + public String getId() { + return this.id; + } + + /** + * Gets the name of this item, or the ID if the name cannot be found. + * + * @return The name, or ID + */ + public String getName() { + return getId(); + } + + @Override + public String toString() { + return getId(); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof EntityType && this.id.equals(((EntityType) obj).id); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java b/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java new file mode 100644 index 0000000..301be1b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java @@ -0,0 +1,166 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.entity; + +import javax.annotation.Nullable; + +/** + * Stores a list of common {@link EntityType EntityTypes}. + * + * @see EntityType + */ +@SuppressWarnings("unused") +public final class EntityTypes { + @Nullable public static final EntityType ALLAY = get("minecraft:allay"); + @Nullable public static final EntityType AREA_EFFECT_CLOUD = get("minecraft:area_effect_cloud"); + @Nullable public static final EntityType ARMOR_STAND = get("minecraft:armor_stand"); + @Nullable public static final EntityType ARROW = get("minecraft:arrow"); + @Nullable public static final EntityType AXOLOTL = get("minecraft:axolotl"); + @Nullable public static final EntityType BAT = get("minecraft:bat"); + @Nullable public static final EntityType BEE = get("minecraft:bee"); + @Nullable public static final EntityType BLAZE = get("minecraft:blaze"); + @Nullable public static final EntityType BLOCK_DISPLAY = get("minecraft:block_display"); + @Nullable public static final EntityType BOAT = get("minecraft:boat"); + @Nullable public static final EntityType CAMEL = get("minecraft:camel"); + @Nullable public static final EntityType CAT = get("minecraft:cat"); + @Nullable public static final EntityType CAVE_SPIDER = get("minecraft:cave_spider"); + @Nullable public static final EntityType CHEST_BOAT = get("minecraft:chest_boat"); + @Nullable public static final EntityType CHEST_MINECART = get("minecraft:chest_minecart"); + @Nullable public static final EntityType CHICKEN = get("minecraft:chicken"); + @Nullable public static final EntityType COD = get("minecraft:cod"); + @Nullable public static final EntityType COMMAND_BLOCK_MINECART = get("minecraft:command_block_minecart"); + @Nullable public static final EntityType COW = get("minecraft:cow"); + @Nullable public static final EntityType CREEPER = get("minecraft:creeper"); + @Nullable public static final EntityType DOLPHIN = get("minecraft:dolphin"); + @Nullable public static final EntityType DONKEY = get("minecraft:donkey"); + @Nullable public static final EntityType DRAGON_FIREBALL = get("minecraft:dragon_fireball"); + @Nullable public static final EntityType DROWNED = get("minecraft:drowned"); + @Nullable public static final EntityType EGG = get("minecraft:egg"); + @Nullable public static final EntityType ELDER_GUARDIAN = get("minecraft:elder_guardian"); + @Nullable public static final EntityType END_CRYSTAL = get("minecraft:end_crystal"); + @Nullable public static final EntityType ENDER_DRAGON = get("minecraft:ender_dragon"); + @Nullable public static final EntityType ENDER_PEARL = get("minecraft:ender_pearl"); + @Nullable public static final EntityType ENDERMAN = get("minecraft:enderman"); + @Nullable public static final EntityType ENDERMITE = get("minecraft:endermite"); + @Nullable public static final EntityType EVOKER = get("minecraft:evoker"); + @Nullable public static final EntityType EVOKER_FANGS = get("minecraft:evoker_fangs"); + @Nullable public static final EntityType EXPERIENCE_BOTTLE = get("minecraft:experience_bottle"); + @Nullable public static final EntityType EXPERIENCE_ORB = get("minecraft:experience_orb"); + @Nullable public static final EntityType EYE_OF_ENDER = get("minecraft:eye_of_ender"); + @Nullable public static final EntityType FALLING_BLOCK = get("minecraft:falling_block"); + @Nullable public static final EntityType FIREBALL = get("minecraft:fireball"); + @Nullable public static final EntityType FIREWORK_ROCKET = get("minecraft:firework_rocket"); + @Nullable public static final EntityType FISHING_BOBBER = get("minecraft:fishing_bobber"); + @Nullable public static final EntityType FOX = get("minecraft:fox"); + @Nullable public static final EntityType FROG = get("minecraft:frog"); + @Nullable public static final EntityType FURNACE_MINECART = get("minecraft:furnace_minecart"); + @Nullable public static final EntityType GHAST = get("minecraft:ghast"); + @Nullable public static final EntityType GIANT = get("minecraft:giant"); + @Nullable public static final EntityType GLOW_ITEM_FRAME = get("minecraft:glow_item_frame"); + @Nullable public static final EntityType GLOW_SQUID = get("minecraft:glow_squid"); + @Nullable public static final EntityType GOAT = get("minecraft:goat"); + @Nullable public static final EntityType GUARDIAN = get("minecraft:guardian"); + @Nullable public static final EntityType HOGLIN = get("minecraft:hoglin"); + @Nullable public static final EntityType HOPPER_MINECART = get("minecraft:hopper_minecart"); + @Nullable public static final EntityType HORSE = get("minecraft:horse"); + @Nullable public static final EntityType HUSK = get("minecraft:husk"); + @Nullable public static final EntityType ILLUSIONER = get("minecraft:illusioner"); + @Nullable public static final EntityType INTERACTION = get("minecraft:interaction"); + @Nullable public static final EntityType IRON_GOLEM = get("minecraft:iron_golem"); + @Nullable public static final EntityType ITEM = get("minecraft:item"); + @Nullable public static final EntityType ITEM_DISPLAY = get("minecraft:item_display"); + @Nullable public static final EntityType ITEM_FRAME = get("minecraft:item_frame"); + @Nullable public static final EntityType LEASH_KNOT = get("minecraft:leash_knot"); + @Nullable public static final EntityType LIGHTNING_BOLT = get("minecraft:lightning_bolt"); + @Nullable public static final EntityType LLAMA = get("minecraft:llama"); + @Nullable public static final EntityType LLAMA_SPIT = get("minecraft:llama_spit"); + @Nullable public static final EntityType MAGMA_CUBE = get("minecraft:magma_cube"); + @Nullable public static final EntityType MARKER = get("minecraft:marker"); + @Nullable public static final EntityType MINECART = get("minecraft:minecart"); + @Nullable public static final EntityType MOOSHROOM = get("minecraft:mooshroom"); + @Nullable public static final EntityType MULE = get("minecraft:mule"); + @Nullable public static final EntityType OCELOT = get("minecraft:ocelot"); + @Nullable public static final EntityType PAINTING = get("minecraft:painting"); + @Nullable public static final EntityType PANDA = get("minecraft:panda"); + @Nullable public static final EntityType PARROT = get("minecraft:parrot"); + @Nullable public static final EntityType PHANTOM = get("minecraft:phantom"); + @Nullable public static final EntityType PIG = get("minecraft:pig"); + @Nullable public static final EntityType PIGLIN = get("minecraft:piglin"); + @Nullable public static final EntityType PIGLIN_BRUTE = get("minecraft:piglin_brute"); + @Nullable public static final EntityType PILLAGER = get("minecraft:pillager"); + @Nullable public static final EntityType PLAYER = get("minecraft:player"); + @Nullable public static final EntityType POLAR_BEAR = get("minecraft:polar_bear"); + @Nullable public static final EntityType POTION = get("minecraft:potion"); + @Nullable public static final EntityType PUFFERFISH = get("minecraft:pufferfish"); + @Nullable public static final EntityType RABBIT = get("minecraft:rabbit"); + @Nullable public static final EntityType RAVAGER = get("minecraft:ravager"); + @Nullable public static final EntityType SALMON = get("minecraft:salmon"); + @Nullable public static final EntityType SHEEP = get("minecraft:sheep"); + @Nullable public static final EntityType SHULKER = get("minecraft:shulker"); + @Nullable public static final EntityType SHULKER_BULLET = get("minecraft:shulker_bullet"); + @Nullable public static final EntityType SILVERFISH = get("minecraft:silverfish"); + @Nullable public static final EntityType SKELETON = get("minecraft:skeleton"); + @Nullable public static final EntityType SKELETON_HORSE = get("minecraft:skeleton_horse"); + @Nullable public static final EntityType SLIME = get("minecraft:slime"); + @Nullable public static final EntityType SMALL_FIREBALL = get("minecraft:small_fireball"); + @Nullable public static final EntityType SNIFFER = get("minecraft:sniffer"); + @Nullable public static final EntityType SNOW_GOLEM = get("minecraft:snow_golem"); + @Nullable public static final EntityType SNOWBALL = get("minecraft:snowball"); + @Nullable public static final EntityType SPAWNER_MINECART = get("minecraft:spawner_minecart"); + @Nullable public static final EntityType SPECTRAL_ARROW = get("minecraft:spectral_arrow"); + @Nullable public static final EntityType SPIDER = get("minecraft:spider"); + @Nullable public static final EntityType SQUID = get("minecraft:squid"); + @Nullable public static final EntityType STRAY = get("minecraft:stray"); + @Nullable public static final EntityType STRIDER = get("minecraft:strider"); + @Nullable public static final EntityType TADPOLE = get("minecraft:tadpole"); + @Nullable public static final EntityType TEXT_DISPLAY = get("minecraft:text_display"); + @Nullable public static final EntityType TNT = get("minecraft:tnt"); + @Nullable public static final EntityType TNT_MINECART = get("minecraft:tnt_minecart"); + @Nullable public static final EntityType TRADER_LLAMA = get("minecraft:trader_llama"); + @Nullable public static final EntityType TRIDENT = get("minecraft:trident"); + @Nullable public static final EntityType TROPICAL_FISH = get("minecraft:tropical_fish"); + @Nullable public static final EntityType TURTLE = get("minecraft:turtle"); + @Nullable public static final EntityType VEX = get("minecraft:vex"); + @Nullable public static final EntityType VILLAGER = get("minecraft:villager"); + @Nullable public static final EntityType VINDICATOR = get("minecraft:vindicator"); + @Nullable public static final EntityType WANDERING_TRADER = get("minecraft:wandering_trader"); + @Nullable public static final EntityType WARDEN = get("minecraft:warden"); + @Nullable public static final EntityType WITCH = get("minecraft:witch"); + @Nullable public static final EntityType WITHER = get("minecraft:wither"); + @Nullable public static final EntityType WITHER_SKELETON = get("minecraft:wither_skeleton"); + @Nullable public static final EntityType WITHER_SKULL = get("minecraft:wither_skull"); + @Nullable public static final EntityType WOLF = get("minecraft:wolf"); + @Nullable public static final EntityType ZOGLIN = get("minecraft:zoglin"); + @Nullable public static final EntityType ZOMBIE = get("minecraft:zombie"); + @Nullable public static final EntityType ZOMBIE_HORSE = get("minecraft:zombie_horse"); + @Deprecated @Nullable public static final EntityType ZOMBIE_PIGMAN = get("minecraft:zombie_pigman"); + @Nullable public static final EntityType ZOMBIE_VILLAGER = get("minecraft:zombie_villager"); + @Nullable public static final EntityType ZOMBIFIED_PIGLIN = get("minecraft:zombified_piglin"); + + private EntityTypes() { + } + + /** + * Gets the {@link EntityType} associated with the given id. + */ + public static @Nullable EntityType get(String id) { + return EntityType.REGISTRY.get(id); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java b/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java new file mode 100644 index 0000000..165223d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java @@ -0,0 +1,46 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.fluid; + +import javax.annotation.Nullable; + +/** + * Stores a list of categories of Block Types. + */ +public final class FluidCategories { + + public static final FluidCategory LAVA = register("minecraft:lava"); + public static final FluidCategory WATER = register("minecraft:water"); + + private FluidCategories() { + } + + private static FluidCategory register(final String id) { + return register(new FluidCategory(id)); + } + + public static FluidCategory register(final FluidCategory tag) { + return FluidCategory.REGISTRY.register(tag.getId(), tag); + } + + public static @Nullable FluidCategory get(final String id) { + return FluidCategory.REGISTRY.get(id); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategory.java b/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategory.java new file mode 100644 index 0000000..b65f19b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategory.java @@ -0,0 +1,48 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.fluid; + +import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; + +import java.util.Collections; +import java.util.Set; + +/** + * A category of fluids. This is due to the splitting up of + * blocks such as wool into separate ids. + */ +public class FluidCategory extends Category implements Keyed { + + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("fluid tag"); + + public FluidCategory(final String id) { + super(id); + } + + @Override + protected Set load() { + return Collections.emptySet(); // TODO Make this work. + // return WorldEdit.getInstance().getPlatformManager() + // .queryCapability(Capability.GAME_HOOKS).getRegistries() + // .getBlockCategoryRegistry().getCategorisedByName(this.id); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java b/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java new file mode 100644 index 0000000..a0e5cb0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java @@ -0,0 +1,63 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.fluid; + +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; + +/** + * Minecraft now has a 'fluid' system. This is a + * stub class to represent what it may be in the future. + */ +public class FluidType implements Keyed { + + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("fluid type"); + + private final String id; + + public FluidType(String id) { + this.id = id; + } + + /** + * Gets the ID of this block. + * + * @return The id + */ + @Override + public String getId() { + return this.id; + } + + @Override + public String toString() { + return getId(); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof FluidType && this.id.equals(((FluidType) obj).id); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java b/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java new file mode 100644 index 0000000..493e077 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.fluid; + +import javax.annotation.Nullable; + +/** + * Stores a list of common Fluid String IDs. + */ +public final class FluidTypes { + + public static final FluidType EMPTY = register("minecraft:empty"); + public static final FluidType FLOWING_LAVA = register("minecraft:flowing_lava"); + public static final FluidType FLOWING_WATER = register("minecraft:flowing_water"); + public static final FluidType LAVA = register("minecraft:lava"); + public static final FluidType WATER = register("minecraft:water"); + + private FluidTypes() { + } + + private static FluidType register(final String id) { + return register(new FluidType(id)); + } + + public static FluidType register(final FluidType fluid) { + return FluidType.REGISTRY.register(fluid.getId(), fluid); + } + + public static @Nullable FluidType get(final String id) { + return FluidType.REGISTRY.get(id); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java b/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java new file mode 100644 index 0000000..312caa3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java @@ -0,0 +1,64 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.gamemode; + +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.Registry; + +public class GameMode implements Keyed { + + public static final Registry REGISTRY = new Registry<>("game mode"); + + private final String id; + + public GameMode(String id) { + this.id = id; + } + + @Override + public String getId() { + return this.id; + } + + /** + * Gets the name of this game mode, or the ID if the name cannot be found. + * + * @return The name, or ID + */ + public String getName() { + return getId(); + } + + @Override + public String toString() { + return getId(); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof GameMode && this.id.equals(((GameMode) obj).id); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java b/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java new file mode 100644 index 0000000..ce87f9c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.gamemode; + +import javax.annotation.Nullable; + +public final class GameModes { + + public static final GameMode SURVIVAL = register("survival"); + public static final GameMode CREATIVE = register("creative"); + public static final GameMode ADVENTURE = register("adventure"); + public static final GameMode SPECTATOR = register("spectator"); + + private GameModes() { + } + + private static GameMode register(final String id) { + return register(new GameMode(id)); + } + + public static GameMode register(final GameMode gameMode) { + return GameMode.REGISTRY.register(gameMode.getId(), gameMode); + } + + @Nullable + public static GameMode get(final String id) { + return GameMode.REGISTRY.get(id); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java b/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java new file mode 100644 index 0000000..91abe02 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java @@ -0,0 +1,146 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.item; + +/** + * Stores a list of common {@link ItemCategory ItemCategories}. + * + * @see ItemCategory + */ +@SuppressWarnings("unused") +public final class ItemCategories { + public static final ItemCategory ACACIA_LOGS = get("minecraft:acacia_logs"); + public static final ItemCategory ANVIL = get("minecraft:anvil"); + public static final ItemCategory ARROWS = get("minecraft:arrows"); + public static final ItemCategory AXES = get("minecraft:axes"); + public static final ItemCategory AXOLOTL_TEMPT_ITEMS = get("minecraft:axolotl_tempt_items"); + public static final ItemCategory BAMBOO_BLOCKS = get("minecraft:bamboo_blocks"); + public static final ItemCategory BANNERS = get("minecraft:banners"); + public static final ItemCategory BEACON_PAYMENT_ITEMS = get("minecraft:beacon_payment_items"); + public static final ItemCategory BEDS = get("minecraft:beds"); + public static final ItemCategory BIRCH_LOGS = get("minecraft:birch_logs"); + public static final ItemCategory BOATS = get("minecraft:boats"); + public static final ItemCategory BOOKSHELF_BOOKS = get("minecraft:bookshelf_books"); + public static final ItemCategory BREAKS_DECORATED_POTS = get("minecraft:breaks_decorated_pots"); + public static final ItemCategory BUTTONS = get("minecraft:buttons"); + public static final ItemCategory CANDLES = get("minecraft:candles"); + @Deprecated public static final ItemCategory CARPETS = get("minecraft:carpets"); + public static final ItemCategory CHERRY_LOGS = get("minecraft:cherry_logs"); + public static final ItemCategory CHEST_BOATS = get("minecraft:chest_boats"); + public static final ItemCategory CLUSTER_MAX_HARVESTABLES = get("minecraft:cluster_max_harvestables"); + public static final ItemCategory COAL_ORES = get("minecraft:coal_ores"); + public static final ItemCategory COALS = get("minecraft:coals"); + public static final ItemCategory COMPASSES = get("minecraft:compasses"); + public static final ItemCategory COMPLETES_FIND_TREE_TUTORIAL = get("minecraft:completes_find_tree_tutorial"); + public static final ItemCategory COPPER_ORES = get("minecraft:copper_ores"); + public static final ItemCategory CREEPER_DROP_MUSIC_DISCS = get("minecraft:creeper_drop_music_discs"); + public static final ItemCategory CREEPER_IGNITERS = get("minecraft:creeper_igniters"); + public static final ItemCategory CRIMSON_STEMS = get("minecraft:crimson_stems"); + public static final ItemCategory DAMPENS_VIBRATIONS = get("minecraft:dampens_vibrations"); + public static final ItemCategory DARK_OAK_LOGS = get("minecraft:dark_oak_logs"); + public static final ItemCategory DECORATED_POT_INGREDIENTS = get("minecraft:decorated_pot_ingredients"); + public static final ItemCategory DECORATED_POT_SHERDS = get("minecraft:decorated_pot_sherds"); + public static final ItemCategory DIAMOND_ORES = get("minecraft:diamond_ores"); + public static final ItemCategory DIRT = get("minecraft:dirt"); + public static final ItemCategory DOORS = get("minecraft:doors"); + public static final ItemCategory EMERALD_ORES = get("minecraft:emerald_ores"); + public static final ItemCategory FENCE_GATES = get("minecraft:fence_gates"); + public static final ItemCategory FENCES = get("minecraft:fences"); + public static final ItemCategory FISHES = get("minecraft:fishes"); + public static final ItemCategory FLOWERS = get("minecraft:flowers"); + public static final ItemCategory FOX_FOOD = get("minecraft:fox_food"); + public static final ItemCategory FREEZE_IMMUNE_WEARABLES = get("minecraft:freeze_immune_wearables"); + @Deprecated public static final ItemCategory FURNACE_MATERIALS = get("minecraft:furnace_materials"); + public static final ItemCategory GOLD_ORES = get("minecraft:gold_ores"); + public static final ItemCategory HANGING_SIGNS = get("minecraft:hanging_signs"); + public static final ItemCategory HOES = get("minecraft:hoes"); + public static final ItemCategory IGNORED_BY_PIGLIN_BABIES = get("minecraft:ignored_by_piglin_babies"); + public static final ItemCategory IRON_ORES = get("minecraft:iron_ores"); + public static final ItemCategory JUNGLE_LOGS = get("minecraft:jungle_logs"); + public static final ItemCategory LAPIS_ORES = get("minecraft:lapis_ores"); + public static final ItemCategory LEAVES = get("minecraft:leaves"); + public static final ItemCategory LECTERN_BOOKS = get("minecraft:lectern_books"); + public static final ItemCategory LOGS = get("minecraft:logs"); + public static final ItemCategory LOGS_THAT_BURN = get("minecraft:logs_that_burn"); + public static final ItemCategory MANGROVE_LOGS = get("minecraft:mangrove_logs"); + public static final ItemCategory MUSIC_DISCS = get("minecraft:music_discs"); + public static final ItemCategory NON_FLAMMABLE_WOOD = get("minecraft:non_flammable_wood"); + public static final ItemCategory NOTEBLOCK_TOP_INSTRUMENTS = get("minecraft:noteblock_top_instruments"); + public static final ItemCategory OAK_LOGS = get("minecraft:oak_logs"); + @Deprecated public static final ItemCategory OCCLUDES_VIBRATION_SIGNALS = get("minecraft:occludes_vibration_signals"); + @Deprecated public static final ItemCategory OVERWORLD_NATURAL_LOGS = get("minecraft:overworld_natural_logs"); + public static final ItemCategory PICKAXES = get("minecraft:pickaxes"); + public static final ItemCategory PIGLIN_FOOD = get("minecraft:piglin_food"); + public static final ItemCategory PIGLIN_LOVED = get("minecraft:piglin_loved"); + public static final ItemCategory PIGLIN_REPELLENTS = get("minecraft:piglin_repellents"); + public static final ItemCategory PLANKS = get("minecraft:planks"); + public static final ItemCategory RAILS = get("minecraft:rails"); + public static final ItemCategory REDSTONE_ORES = get("minecraft:redstone_ores"); + public static final ItemCategory SAND = get("minecraft:sand"); + public static final ItemCategory SAPLINGS = get("minecraft:saplings"); + public static final ItemCategory SHOVELS = get("minecraft:shovels"); + public static final ItemCategory SIGNS = get("minecraft:signs"); + public static final ItemCategory SLABS = get("minecraft:slabs"); + public static final ItemCategory SMALL_FLOWERS = get("minecraft:small_flowers"); + public static final ItemCategory SMELTS_TO_GLASS = get("minecraft:smelts_to_glass"); + public static final ItemCategory SNIFFER_FOOD = get("minecraft:sniffer_food"); + public static final ItemCategory SOUL_FIRE_BASE_BLOCKS = get("minecraft:soul_fire_base_blocks"); + public static final ItemCategory SPRUCE_LOGS = get("minecraft:spruce_logs"); + public static final ItemCategory STAIRS = get("minecraft:stairs"); + public static final ItemCategory STONE_BRICKS = get("minecraft:stone_bricks"); + public static final ItemCategory STONE_BUTTONS = get("minecraft:stone_buttons"); + public static final ItemCategory STONE_CRAFTING_MATERIALS = get("minecraft:stone_crafting_materials"); + public static final ItemCategory STONE_TOOL_MATERIALS = get("minecraft:stone_tool_materials"); + public static final ItemCategory SWORDS = get("minecraft:swords"); + public static final ItemCategory TALL_FLOWERS = get("minecraft:tall_flowers"); + public static final ItemCategory TERRACOTTA = get("minecraft:terracotta"); + public static final ItemCategory TOOLS = get("minecraft:tools"); + public static final ItemCategory TRAPDOORS = get("minecraft:trapdoors"); + public static final ItemCategory TRIM_MATERIALS = get("minecraft:trim_materials"); + public static final ItemCategory TRIM_TEMPLATES = get("minecraft:trim_templates"); + public static final ItemCategory TRIMMABLE_ARMOR = get("minecraft:trimmable_armor"); + public static final ItemCategory VILLAGER_PLANTABLE_SEEDS = get("minecraft:villager_plantable_seeds"); + public static final ItemCategory WALLS = get("minecraft:walls"); + public static final ItemCategory WARPED_STEMS = get("minecraft:warped_stems"); + public static final ItemCategory WART_BLOCKS = get("minecraft:wart_blocks"); + public static final ItemCategory WOODEN_BUTTONS = get("minecraft:wooden_buttons"); + public static final ItemCategory WOODEN_DOORS = get("minecraft:wooden_doors"); + public static final ItemCategory WOODEN_FENCES = get("minecraft:wooden_fences"); + public static final ItemCategory WOODEN_PRESSURE_PLATES = get("minecraft:wooden_pressure_plates"); + public static final ItemCategory WOODEN_SLABS = get("minecraft:wooden_slabs"); + public static final ItemCategory WOODEN_STAIRS = get("minecraft:wooden_stairs"); + public static final ItemCategory WOODEN_TRAPDOORS = get("minecraft:wooden_trapdoors"); + public static final ItemCategory WOOL = get("minecraft:wool"); + public static final ItemCategory WOOL_CARPETS = get("minecraft:wool_carpets"); + + private ItemCategories() { + } + + /** + * Gets the {@link ItemCategory} associated with the given id. + */ + public static ItemCategory get(String id) { + ItemCategory entry = ItemCategory.REGISTRY.get(id); + if (entry == null) { + return new ItemCategory(id); + } + return entry; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/item/ItemCategory.java b/src/main/java/com/sk89q/worldedit/world/item/ItemCategory.java new file mode 100644 index 0000000..4850b1c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/item/ItemCategory.java @@ -0,0 +1,60 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.item; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; + +import java.util.Set; + +/** + * A category of items. This is due to the splitting up of + * items such as wool into separate ids. + */ +public class ItemCategory extends Category implements Keyed { + + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("item tag"); + + public ItemCategory(final String id) { + super(id); + } + + @Override + protected Set load() { + return WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries() + .getItemCategoryRegistry().getAll(this); + } + + /** + * Checks whether the BaseItem is contained within + * this category. + * + * @param baseItem The item + * @return If it's a part of this category + */ + public boolean contains(BaseItem baseItem) { + return this.getAll().contains(baseItem.getType()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/item/ItemType.java b/src/main/java/com/sk89q/worldedit/world/item/ItemType.java new file mode 100644 index 0000000..833560a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/item/ItemType.java @@ -0,0 +1,129 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.item; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; +import com.sk89q.worldedit.util.GuavaUtil; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import net.kyori.text.Component; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.registry.ItemMaterial; + +import javax.annotation.Nullable; + +public class ItemType implements Keyed { + + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("item type", true); + + private final String id; + @SuppressWarnings("deprecation") + private final LazyReference name = LazyReference.from(() -> { + String name = GuavaUtil.firstNonNull( + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS) + .getRegistries().getItemRegistry().getName(this), + "" + ); + return name.isEmpty() ? getId() : name; + }); + private final LazyReference richName = LazyReference.from(() -> + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS) + .getRegistries().getItemRegistry().getRichName(this) + ); + private final LazyReference itemMaterial = LazyReference.from(() -> + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS) + .getRegistries().getItemRegistry().getMaterial(this) + ); + + public ItemType(String id) { + // If it has no namespace, assume minecraft. + if (!id.contains(":")) { + id = "minecraft:" + id; + } + this.id = id; + } + + @Override + public String getId() { + return this.id; + } + + public Component getRichName() { + return richName.getValue(); + } + + /** + * Gets the name of this item, or the ID if the name cannot be found. + * + * @return The name, or ID + * @deprecated Names are translatable now, use {@link #getRichName()}. + */ + @Deprecated + public String getName() { + return name.getValue(); + } + + + /** + * Gets whether this item type has a block representation. + * + * @return If it has a block + */ + public boolean hasBlockType() { + return getBlockType() != null; + } + + /** + * Gets the block representation of this item type, if it exists. + * + * @return The block representation + */ + @Nullable + public BlockType getBlockType() { + return BlockTypes.get(this.id); + } + + /** + * Get the material for this ItemType. + * + * @return The material + */ + public ItemMaterial getMaterial() { + return itemMaterial.getValue(); + } + + @Override + public String toString() { + return getId(); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof ItemType && this.id.equals(((ItemType) obj).id); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java b/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java new file mode 100644 index 0000000..e87ae40 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java @@ -0,0 +1,1302 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.item; + +import javax.annotation.Nullable; + +/** + * Stores a list of common {@link ItemType ItemTypes}. + * + * @see ItemType + */ +@SuppressWarnings("unused") +public final class ItemTypes { + @Nullable public static final ItemType ACACIA_BOAT = get("minecraft:acacia_boat"); + @Nullable public static final ItemType ACACIA_BUTTON = get("minecraft:acacia_button"); + @Nullable public static final ItemType ACACIA_CHEST_BOAT = get("minecraft:acacia_chest_boat"); + @Nullable public static final ItemType ACACIA_DOOR = get("minecraft:acacia_door"); + @Nullable public static final ItemType ACACIA_FENCE = get("minecraft:acacia_fence"); + @Nullable public static final ItemType ACACIA_FENCE_GATE = get("minecraft:acacia_fence_gate"); + @Nullable public static final ItemType ACACIA_HANGING_SIGN = get("minecraft:acacia_hanging_sign"); + @Nullable public static final ItemType ACACIA_LEAVES = get("minecraft:acacia_leaves"); + @Nullable public static final ItemType ACACIA_LOG = get("minecraft:acacia_log"); + @Nullable public static final ItemType ACACIA_PLANKS = get("minecraft:acacia_planks"); + @Nullable public static final ItemType ACACIA_PRESSURE_PLATE = get("minecraft:acacia_pressure_plate"); + @Nullable public static final ItemType ACACIA_SAPLING = get("minecraft:acacia_sapling"); + @Nullable public static final ItemType ACACIA_SIGN = get("minecraft:acacia_sign"); + @Nullable public static final ItemType ACACIA_SLAB = get("minecraft:acacia_slab"); + @Nullable public static final ItemType ACACIA_STAIRS = get("minecraft:acacia_stairs"); + @Nullable public static final ItemType ACACIA_TRAPDOOR = get("minecraft:acacia_trapdoor"); + @Nullable public static final ItemType ACACIA_WOOD = get("minecraft:acacia_wood"); + @Nullable public static final ItemType ACTIVATOR_RAIL = get("minecraft:activator_rail"); + @Nullable public static final ItemType AIR = get("minecraft:air"); + @Nullable public static final ItemType ALLAY_SPAWN_EGG = get("minecraft:allay_spawn_egg"); + @Nullable public static final ItemType ALLIUM = get("minecraft:allium"); + @Nullable public static final ItemType AMETHYST_BLOCK = get("minecraft:amethyst_block"); + @Nullable public static final ItemType AMETHYST_CLUSTER = get("minecraft:amethyst_cluster"); + @Nullable public static final ItemType AMETHYST_SHARD = get("minecraft:amethyst_shard"); + @Nullable public static final ItemType ANCIENT_DEBRIS = get("minecraft:ancient_debris"); + @Nullable public static final ItemType ANDESITE = get("minecraft:andesite"); + @Nullable public static final ItemType ANDESITE_SLAB = get("minecraft:andesite_slab"); + @Nullable public static final ItemType ANDESITE_STAIRS = get("minecraft:andesite_stairs"); + @Nullable public static final ItemType ANDESITE_WALL = get("minecraft:andesite_wall"); + @Nullable public static final ItemType ANGLER_POTTERY_SHERD = get("minecraft:angler_pottery_sherd"); + @Nullable public static final ItemType ANVIL = get("minecraft:anvil"); + @Nullable public static final ItemType APPLE = get("minecraft:apple"); + @Nullable public static final ItemType ARCHER_POTTERY_SHERD = get("minecraft:archer_pottery_sherd"); + @Nullable public static final ItemType ARMOR_STAND = get("minecraft:armor_stand"); + @Nullable public static final ItemType ARMS_UP_POTTERY_SHERD = get("minecraft:arms_up_pottery_sherd"); + @Nullable public static final ItemType ARROW = get("minecraft:arrow"); + @Nullable public static final ItemType AXOLOTL_BUCKET = get("minecraft:axolotl_bucket"); + @Nullable public static final ItemType AXOLOTL_SPAWN_EGG = get("minecraft:axolotl_spawn_egg"); + @Nullable public static final ItemType AZALEA = get("minecraft:azalea"); + @Nullable public static final ItemType AZALEA_LEAVES = get("minecraft:azalea_leaves"); + @Nullable public static final ItemType AZURE_BLUET = get("minecraft:azure_bluet"); + @Nullable public static final ItemType BAKED_POTATO = get("minecraft:baked_potato"); + @Nullable public static final ItemType BAMBOO = get("minecraft:bamboo"); + @Nullable public static final ItemType BAMBOO_BLOCK = get("minecraft:bamboo_block"); + @Nullable public static final ItemType BAMBOO_BUTTON = get("minecraft:bamboo_button"); + @Nullable public static final ItemType BAMBOO_CHEST_RAFT = get("minecraft:bamboo_chest_raft"); + @Nullable public static final ItemType BAMBOO_DOOR = get("minecraft:bamboo_door"); + @Nullable public static final ItemType BAMBOO_FENCE = get("minecraft:bamboo_fence"); + @Nullable public static final ItemType BAMBOO_FENCE_GATE = get("minecraft:bamboo_fence_gate"); + @Nullable public static final ItemType BAMBOO_HANGING_SIGN = get("minecraft:bamboo_hanging_sign"); + @Nullable public static final ItemType BAMBOO_MOSAIC = get("minecraft:bamboo_mosaic"); + @Nullable public static final ItemType BAMBOO_MOSAIC_SLAB = get("minecraft:bamboo_mosaic_slab"); + @Nullable public static final ItemType BAMBOO_MOSAIC_STAIRS = get("minecraft:bamboo_mosaic_stairs"); + @Nullable public static final ItemType BAMBOO_PLANKS = get("minecraft:bamboo_planks"); + @Nullable public static final ItemType BAMBOO_PRESSURE_PLATE = get("minecraft:bamboo_pressure_plate"); + @Nullable public static final ItemType BAMBOO_RAFT = get("minecraft:bamboo_raft"); + @Nullable public static final ItemType BAMBOO_SIGN = get("minecraft:bamboo_sign"); + @Nullable public static final ItemType BAMBOO_SLAB = get("minecraft:bamboo_slab"); + @Nullable public static final ItemType BAMBOO_STAIRS = get("minecraft:bamboo_stairs"); + @Nullable public static final ItemType BAMBOO_TRAPDOOR = get("minecraft:bamboo_trapdoor"); + @Nullable public static final ItemType BARREL = get("minecraft:barrel"); + @Nullable public static final ItemType BARRIER = get("minecraft:barrier"); + @Nullable public static final ItemType BASALT = get("minecraft:basalt"); + @Nullable public static final ItemType BAT_SPAWN_EGG = get("minecraft:bat_spawn_egg"); + @Nullable public static final ItemType BEACON = get("minecraft:beacon"); + @Nullable public static final ItemType BEDROCK = get("minecraft:bedrock"); + @Nullable public static final ItemType BEE_NEST = get("minecraft:bee_nest"); + @Nullable public static final ItemType BEE_SPAWN_EGG = get("minecraft:bee_spawn_egg"); + @Nullable public static final ItemType BEEF = get("minecraft:beef"); + @Nullable public static final ItemType BEEHIVE = get("minecraft:beehive"); + @Nullable public static final ItemType BEETROOT = get("minecraft:beetroot"); + @Nullable public static final ItemType BEETROOT_SEEDS = get("minecraft:beetroot_seeds"); + @Nullable public static final ItemType BEETROOT_SOUP = get("minecraft:beetroot_soup"); + @Nullable public static final ItemType BELL = get("minecraft:bell"); + @Nullable public static final ItemType BIG_DRIPLEAF = get("minecraft:big_dripleaf"); + @Nullable public static final ItemType BIRCH_BOAT = get("minecraft:birch_boat"); + @Nullable public static final ItemType BIRCH_BUTTON = get("minecraft:birch_button"); + @Nullable public static final ItemType BIRCH_CHEST_BOAT = get("minecraft:birch_chest_boat"); + @Nullable public static final ItemType BIRCH_DOOR = get("minecraft:birch_door"); + @Nullable public static final ItemType BIRCH_FENCE = get("minecraft:birch_fence"); + @Nullable public static final ItemType BIRCH_FENCE_GATE = get("minecraft:birch_fence_gate"); + @Nullable public static final ItemType BIRCH_HANGING_SIGN = get("minecraft:birch_hanging_sign"); + @Nullable public static final ItemType BIRCH_LEAVES = get("minecraft:birch_leaves"); + @Nullable public static final ItemType BIRCH_LOG = get("minecraft:birch_log"); + @Nullable public static final ItemType BIRCH_PLANKS = get("minecraft:birch_planks"); + @Nullable public static final ItemType BIRCH_PRESSURE_PLATE = get("minecraft:birch_pressure_plate"); + @Nullable public static final ItemType BIRCH_SAPLING = get("minecraft:birch_sapling"); + @Nullable public static final ItemType BIRCH_SIGN = get("minecraft:birch_sign"); + @Nullable public static final ItemType BIRCH_SLAB = get("minecraft:birch_slab"); + @Nullable public static final ItemType BIRCH_STAIRS = get("minecraft:birch_stairs"); + @Nullable public static final ItemType BIRCH_TRAPDOOR = get("minecraft:birch_trapdoor"); + @Nullable public static final ItemType BIRCH_WOOD = get("minecraft:birch_wood"); + @Nullable public static final ItemType BLACK_BANNER = get("minecraft:black_banner"); + @Nullable public static final ItemType BLACK_BED = get("minecraft:black_bed"); + @Nullable public static final ItemType BLACK_CANDLE = get("minecraft:black_candle"); + @Nullable public static final ItemType BLACK_CARPET = get("minecraft:black_carpet"); + @Nullable public static final ItemType BLACK_CONCRETE = get("minecraft:black_concrete"); + @Nullable public static final ItemType BLACK_CONCRETE_POWDER = get("minecraft:black_concrete_powder"); + @Nullable public static final ItemType BLACK_DYE = get("minecraft:black_dye"); + @Nullable public static final ItemType BLACK_GLAZED_TERRACOTTA = get("minecraft:black_glazed_terracotta"); + @Nullable public static final ItemType BLACK_SHULKER_BOX = get("minecraft:black_shulker_box"); + @Nullable public static final ItemType BLACK_STAINED_GLASS = get("minecraft:black_stained_glass"); + @Nullable public static final ItemType BLACK_STAINED_GLASS_PANE = get("minecraft:black_stained_glass_pane"); + @Nullable public static final ItemType BLACK_TERRACOTTA = get("minecraft:black_terracotta"); + @Nullable public static final ItemType BLACK_WOOL = get("minecraft:black_wool"); + @Nullable public static final ItemType BLACKSTONE = get("minecraft:blackstone"); + @Nullable public static final ItemType BLACKSTONE_SLAB = get("minecraft:blackstone_slab"); + @Nullable public static final ItemType BLACKSTONE_STAIRS = get("minecraft:blackstone_stairs"); + @Nullable public static final ItemType BLACKSTONE_WALL = get("minecraft:blackstone_wall"); + @Nullable public static final ItemType BLADE_POTTERY_SHERD = get("minecraft:blade_pottery_sherd"); + @Nullable public static final ItemType BLAST_FURNACE = get("minecraft:blast_furnace"); + @Nullable public static final ItemType BLAZE_POWDER = get("minecraft:blaze_powder"); + @Nullable public static final ItemType BLAZE_ROD = get("minecraft:blaze_rod"); + @Nullable public static final ItemType BLAZE_SPAWN_EGG = get("minecraft:blaze_spawn_egg"); + @Nullable public static final ItemType BLUE_BANNER = get("minecraft:blue_banner"); + @Nullable public static final ItemType BLUE_BED = get("minecraft:blue_bed"); + @Nullable public static final ItemType BLUE_CANDLE = get("minecraft:blue_candle"); + @Nullable public static final ItemType BLUE_CARPET = get("minecraft:blue_carpet"); + @Nullable public static final ItemType BLUE_CONCRETE = get("minecraft:blue_concrete"); + @Nullable public static final ItemType BLUE_CONCRETE_POWDER = get("minecraft:blue_concrete_powder"); + @Nullable public static final ItemType BLUE_DYE = get("minecraft:blue_dye"); + @Nullable public static final ItemType BLUE_GLAZED_TERRACOTTA = get("minecraft:blue_glazed_terracotta"); + @Nullable public static final ItemType BLUE_ICE = get("minecraft:blue_ice"); + @Nullable public static final ItemType BLUE_ORCHID = get("minecraft:blue_orchid"); + @Nullable public static final ItemType BLUE_SHULKER_BOX = get("minecraft:blue_shulker_box"); + @Nullable public static final ItemType BLUE_STAINED_GLASS = get("minecraft:blue_stained_glass"); + @Nullable public static final ItemType BLUE_STAINED_GLASS_PANE = get("minecraft:blue_stained_glass_pane"); + @Nullable public static final ItemType BLUE_TERRACOTTA = get("minecraft:blue_terracotta"); + @Nullable public static final ItemType BLUE_WOOL = get("minecraft:blue_wool"); + @Nullable public static final ItemType BONE = get("minecraft:bone"); + @Nullable public static final ItemType BONE_BLOCK = get("minecraft:bone_block"); + @Nullable public static final ItemType BONE_MEAL = get("minecraft:bone_meal"); + @Nullable public static final ItemType BOOK = get("minecraft:book"); + @Nullable public static final ItemType BOOKSHELF = get("minecraft:bookshelf"); + @Nullable public static final ItemType BOW = get("minecraft:bow"); + @Nullable public static final ItemType BOWL = get("minecraft:bowl"); + @Nullable public static final ItemType BRAIN_CORAL = get("minecraft:brain_coral"); + @Nullable public static final ItemType BRAIN_CORAL_BLOCK = get("minecraft:brain_coral_block"); + @Nullable public static final ItemType BRAIN_CORAL_FAN = get("minecraft:brain_coral_fan"); + @Nullable public static final ItemType BREAD = get("minecraft:bread"); + @Nullable public static final ItemType BREWER_POTTERY_SHERD = get("minecraft:brewer_pottery_sherd"); + @Nullable public static final ItemType BREWING_STAND = get("minecraft:brewing_stand"); + @Nullable public static final ItemType BRICK = get("minecraft:brick"); + @Nullable public static final ItemType BRICK_SLAB = get("minecraft:brick_slab"); + @Nullable public static final ItemType BRICK_STAIRS = get("minecraft:brick_stairs"); + @Nullable public static final ItemType BRICK_WALL = get("minecraft:brick_wall"); + @Nullable public static final ItemType BRICKS = get("minecraft:bricks"); + @Nullable public static final ItemType BROWN_BANNER = get("minecraft:brown_banner"); + @Nullable public static final ItemType BROWN_BED = get("minecraft:brown_bed"); + @Nullable public static final ItemType BROWN_CANDLE = get("minecraft:brown_candle"); + @Nullable public static final ItemType BROWN_CARPET = get("minecraft:brown_carpet"); + @Nullable public static final ItemType BROWN_CONCRETE = get("minecraft:brown_concrete"); + @Nullable public static final ItemType BROWN_CONCRETE_POWDER = get("minecraft:brown_concrete_powder"); + @Nullable public static final ItemType BROWN_DYE = get("minecraft:brown_dye"); + @Nullable public static final ItemType BROWN_GLAZED_TERRACOTTA = get("minecraft:brown_glazed_terracotta"); + @Nullable public static final ItemType BROWN_MUSHROOM = get("minecraft:brown_mushroom"); + @Nullable public static final ItemType BROWN_MUSHROOM_BLOCK = get("minecraft:brown_mushroom_block"); + @Nullable public static final ItemType BROWN_SHULKER_BOX = get("minecraft:brown_shulker_box"); + @Nullable public static final ItemType BROWN_STAINED_GLASS = get("minecraft:brown_stained_glass"); + @Nullable public static final ItemType BROWN_STAINED_GLASS_PANE = get("minecraft:brown_stained_glass_pane"); + @Nullable public static final ItemType BROWN_TERRACOTTA = get("minecraft:brown_terracotta"); + @Nullable public static final ItemType BROWN_WOOL = get("minecraft:brown_wool"); + @Nullable public static final ItemType BRUSH = get("minecraft:brush"); + @Nullable public static final ItemType BUBBLE_CORAL = get("minecraft:bubble_coral"); + @Nullable public static final ItemType BUBBLE_CORAL_BLOCK = get("minecraft:bubble_coral_block"); + @Nullable public static final ItemType BUBBLE_CORAL_FAN = get("minecraft:bubble_coral_fan"); + @Nullable public static final ItemType BUCKET = get("minecraft:bucket"); + @Nullable public static final ItemType BUDDING_AMETHYST = get("minecraft:budding_amethyst"); + @Nullable public static final ItemType BUNDLE = get("minecraft:bundle"); + @Nullable public static final ItemType BURN_POTTERY_SHERD = get("minecraft:burn_pottery_sherd"); + @Nullable public static final ItemType CACTUS = get("minecraft:cactus"); + @Deprecated @Nullable public static final ItemType CACTUS_GREEN = get("minecraft:cactus_green"); + @Nullable public static final ItemType CAKE = get("minecraft:cake"); + @Nullable public static final ItemType CALCITE = get("minecraft:calcite"); + @Nullable public static final ItemType CALIBRATED_SCULK_SENSOR = get("minecraft:calibrated_sculk_sensor"); + @Nullable public static final ItemType CAMEL_SPAWN_EGG = get("minecraft:camel_spawn_egg"); + @Nullable public static final ItemType CAMPFIRE = get("minecraft:campfire"); + @Nullable public static final ItemType CANDLE = get("minecraft:candle"); + @Nullable public static final ItemType CARROT = get("minecraft:carrot"); + @Nullable public static final ItemType CARROT_ON_A_STICK = get("minecraft:carrot_on_a_stick"); + @Nullable public static final ItemType CARTOGRAPHY_TABLE = get("minecraft:cartography_table"); + @Nullable public static final ItemType CARVED_PUMPKIN = get("minecraft:carved_pumpkin"); + @Nullable public static final ItemType CAT_SPAWN_EGG = get("minecraft:cat_spawn_egg"); + @Nullable public static final ItemType CAULDRON = get("minecraft:cauldron"); + @Nullable public static final ItemType CAVE_SPIDER_SPAWN_EGG = get("minecraft:cave_spider_spawn_egg"); + @Nullable public static final ItemType CHAIN = get("minecraft:chain"); + @Nullable public static final ItemType CHAIN_COMMAND_BLOCK = get("minecraft:chain_command_block"); + @Nullable public static final ItemType CHAINMAIL_BOOTS = get("minecraft:chainmail_boots"); + @Nullable public static final ItemType CHAINMAIL_CHESTPLATE = get("minecraft:chainmail_chestplate"); + @Nullable public static final ItemType CHAINMAIL_HELMET = get("minecraft:chainmail_helmet"); + @Nullable public static final ItemType CHAINMAIL_LEGGINGS = get("minecraft:chainmail_leggings"); + @Nullable public static final ItemType CHARCOAL = get("minecraft:charcoal"); + @Nullable public static final ItemType CHERRY_BOAT = get("minecraft:cherry_boat"); + @Nullable public static final ItemType CHERRY_BUTTON = get("minecraft:cherry_button"); + @Nullable public static final ItemType CHERRY_CHEST_BOAT = get("minecraft:cherry_chest_boat"); + @Nullable public static final ItemType CHERRY_DOOR = get("minecraft:cherry_door"); + @Nullable public static final ItemType CHERRY_FENCE = get("minecraft:cherry_fence"); + @Nullable public static final ItemType CHERRY_FENCE_GATE = get("minecraft:cherry_fence_gate"); + @Nullable public static final ItemType CHERRY_HANGING_SIGN = get("minecraft:cherry_hanging_sign"); + @Nullable public static final ItemType CHERRY_LEAVES = get("minecraft:cherry_leaves"); + @Nullable public static final ItemType CHERRY_LOG = get("minecraft:cherry_log"); + @Nullable public static final ItemType CHERRY_PLANKS = get("minecraft:cherry_planks"); + @Nullable public static final ItemType CHERRY_PRESSURE_PLATE = get("minecraft:cherry_pressure_plate"); + @Nullable public static final ItemType CHERRY_SAPLING = get("minecraft:cherry_sapling"); + @Nullable public static final ItemType CHERRY_SIGN = get("minecraft:cherry_sign"); + @Nullable public static final ItemType CHERRY_SLAB = get("minecraft:cherry_slab"); + @Nullable public static final ItemType CHERRY_STAIRS = get("minecraft:cherry_stairs"); + @Nullable public static final ItemType CHERRY_TRAPDOOR = get("minecraft:cherry_trapdoor"); + @Nullable public static final ItemType CHERRY_WOOD = get("minecraft:cherry_wood"); + @Nullable public static final ItemType CHEST = get("minecraft:chest"); + @Nullable public static final ItemType CHEST_MINECART = get("minecraft:chest_minecart"); + @Nullable public static final ItemType CHICKEN = get("minecraft:chicken"); + @Nullable public static final ItemType CHICKEN_SPAWN_EGG = get("minecraft:chicken_spawn_egg"); + @Nullable public static final ItemType CHIPPED_ANVIL = get("minecraft:chipped_anvil"); + @Nullable public static final ItemType CHISELED_BOOKSHELF = get("minecraft:chiseled_bookshelf"); + @Nullable public static final ItemType CHISELED_DEEPSLATE = get("minecraft:chiseled_deepslate"); + @Nullable public static final ItemType CHISELED_NETHER_BRICKS = get("minecraft:chiseled_nether_bricks"); + @Nullable public static final ItemType CHISELED_POLISHED_BLACKSTONE = get("minecraft:chiseled_polished_blackstone"); + @Nullable public static final ItemType CHISELED_QUARTZ_BLOCK = get("minecraft:chiseled_quartz_block"); + @Nullable public static final ItemType CHISELED_RED_SANDSTONE = get("minecraft:chiseled_red_sandstone"); + @Nullable public static final ItemType CHISELED_SANDSTONE = get("minecraft:chiseled_sandstone"); + @Nullable public static final ItemType CHISELED_STONE_BRICKS = get("minecraft:chiseled_stone_bricks"); + @Nullable public static final ItemType CHORUS_FLOWER = get("minecraft:chorus_flower"); + @Nullable public static final ItemType CHORUS_FRUIT = get("minecraft:chorus_fruit"); + @Nullable public static final ItemType CHORUS_PLANT = get("minecraft:chorus_plant"); + @Nullable public static final ItemType CLAY = get("minecraft:clay"); + @Nullable public static final ItemType CLAY_BALL = get("minecraft:clay_ball"); + @Nullable public static final ItemType CLOCK = get("minecraft:clock"); + @Nullable public static final ItemType COAL = get("minecraft:coal"); + @Nullable public static final ItemType COAL_BLOCK = get("minecraft:coal_block"); + @Nullable public static final ItemType COAL_ORE = get("minecraft:coal_ore"); + @Nullable public static final ItemType COARSE_DIRT = get("minecraft:coarse_dirt"); + @Nullable public static final ItemType COAST_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:coast_armor_trim_smithing_template"); + @Nullable public static final ItemType COBBLED_DEEPSLATE = get("minecraft:cobbled_deepslate"); + @Nullable public static final ItemType COBBLED_DEEPSLATE_SLAB = get("minecraft:cobbled_deepslate_slab"); + @Nullable public static final ItemType COBBLED_DEEPSLATE_STAIRS = get("minecraft:cobbled_deepslate_stairs"); + @Nullable public static final ItemType COBBLED_DEEPSLATE_WALL = get("minecraft:cobbled_deepslate_wall"); + @Nullable public static final ItemType COBBLESTONE = get("minecraft:cobblestone"); + @Nullable public static final ItemType COBBLESTONE_SLAB = get("minecraft:cobblestone_slab"); + @Nullable public static final ItemType COBBLESTONE_STAIRS = get("minecraft:cobblestone_stairs"); + @Nullable public static final ItemType COBBLESTONE_WALL = get("minecraft:cobblestone_wall"); + @Nullable public static final ItemType COBWEB = get("minecraft:cobweb"); + @Nullable public static final ItemType COCOA_BEANS = get("minecraft:cocoa_beans"); + @Nullable public static final ItemType COD = get("minecraft:cod"); + @Nullable public static final ItemType COD_BUCKET = get("minecraft:cod_bucket"); + @Nullable public static final ItemType COD_SPAWN_EGG = get("minecraft:cod_spawn_egg"); + @Nullable public static final ItemType COMMAND_BLOCK = get("minecraft:command_block"); + @Nullable public static final ItemType COMMAND_BLOCK_MINECART = get("minecraft:command_block_minecart"); + @Nullable public static final ItemType COMPARATOR = get("minecraft:comparator"); + @Nullable public static final ItemType COMPASS = get("minecraft:compass"); + @Nullable public static final ItemType COMPOSTER = get("minecraft:composter"); + @Nullable public static final ItemType CONDUIT = get("minecraft:conduit"); + @Nullable public static final ItemType COOKED_BEEF = get("minecraft:cooked_beef"); + @Nullable public static final ItemType COOKED_CHICKEN = get("minecraft:cooked_chicken"); + @Nullable public static final ItemType COOKED_COD = get("minecraft:cooked_cod"); + @Nullable public static final ItemType COOKED_MUTTON = get("minecraft:cooked_mutton"); + @Nullable public static final ItemType COOKED_PORKCHOP = get("minecraft:cooked_porkchop"); + @Nullable public static final ItemType COOKED_RABBIT = get("minecraft:cooked_rabbit"); + @Nullable public static final ItemType COOKED_SALMON = get("minecraft:cooked_salmon"); + @Nullable public static final ItemType COOKIE = get("minecraft:cookie"); + @Nullable public static final ItemType COPPER_BLOCK = get("minecraft:copper_block"); + @Nullable public static final ItemType COPPER_INGOT = get("minecraft:copper_ingot"); + @Nullable public static final ItemType COPPER_ORE = get("minecraft:copper_ore"); + @Nullable public static final ItemType CORNFLOWER = get("minecraft:cornflower"); + @Nullable public static final ItemType COW_SPAWN_EGG = get("minecraft:cow_spawn_egg"); + @Nullable public static final ItemType CRACKED_DEEPSLATE_BRICKS = get("minecraft:cracked_deepslate_bricks"); + @Nullable public static final ItemType CRACKED_DEEPSLATE_TILES = get("minecraft:cracked_deepslate_tiles"); + @Nullable public static final ItemType CRACKED_NETHER_BRICKS = get("minecraft:cracked_nether_bricks"); + @Nullable public static final ItemType CRACKED_POLISHED_BLACKSTONE_BRICKS = get("minecraft:cracked_polished_blackstone_bricks"); + @Nullable public static final ItemType CRACKED_STONE_BRICKS = get("minecraft:cracked_stone_bricks"); + @Nullable public static final ItemType CRAFTING_TABLE = get("minecraft:crafting_table"); + @Nullable public static final ItemType CREEPER_BANNER_PATTERN = get("minecraft:creeper_banner_pattern"); + @Nullable public static final ItemType CREEPER_HEAD = get("minecraft:creeper_head"); + @Nullable public static final ItemType CREEPER_SPAWN_EGG = get("minecraft:creeper_spawn_egg"); + @Nullable public static final ItemType CRIMSON_BUTTON = get("minecraft:crimson_button"); + @Nullable public static final ItemType CRIMSON_DOOR = get("minecraft:crimson_door"); + @Nullable public static final ItemType CRIMSON_FENCE = get("minecraft:crimson_fence"); + @Nullable public static final ItemType CRIMSON_FENCE_GATE = get("minecraft:crimson_fence_gate"); + @Nullable public static final ItemType CRIMSON_FUNGUS = get("minecraft:crimson_fungus"); + @Nullable public static final ItemType CRIMSON_HANGING_SIGN = get("minecraft:crimson_hanging_sign"); + @Nullable public static final ItemType CRIMSON_HYPHAE = get("minecraft:crimson_hyphae"); + @Nullable public static final ItemType CRIMSON_NYLIUM = get("minecraft:crimson_nylium"); + @Nullable public static final ItemType CRIMSON_PLANKS = get("minecraft:crimson_planks"); + @Nullable public static final ItemType CRIMSON_PRESSURE_PLATE = get("minecraft:crimson_pressure_plate"); + @Nullable public static final ItemType CRIMSON_ROOTS = get("minecraft:crimson_roots"); + @Nullable public static final ItemType CRIMSON_SIGN = get("minecraft:crimson_sign"); + @Nullable public static final ItemType CRIMSON_SLAB = get("minecraft:crimson_slab"); + @Nullable public static final ItemType CRIMSON_STAIRS = get("minecraft:crimson_stairs"); + @Nullable public static final ItemType CRIMSON_STEM = get("minecraft:crimson_stem"); + @Nullable public static final ItemType CRIMSON_TRAPDOOR = get("minecraft:crimson_trapdoor"); + @Nullable public static final ItemType CROSSBOW = get("minecraft:crossbow"); + @Nullable public static final ItemType CRYING_OBSIDIAN = get("minecraft:crying_obsidian"); + @Nullable public static final ItemType CUT_COPPER = get("minecraft:cut_copper"); + @Nullable public static final ItemType CUT_COPPER_SLAB = get("minecraft:cut_copper_slab"); + @Nullable public static final ItemType CUT_COPPER_STAIRS = get("minecraft:cut_copper_stairs"); + @Nullable public static final ItemType CUT_RED_SANDSTONE = get("minecraft:cut_red_sandstone"); + @Nullable public static final ItemType CUT_RED_SANDSTONE_SLAB = get("minecraft:cut_red_sandstone_slab"); + @Nullable public static final ItemType CUT_SANDSTONE = get("minecraft:cut_sandstone"); + @Nullable public static final ItemType CUT_SANDSTONE_SLAB = get("minecraft:cut_sandstone_slab"); + @Nullable public static final ItemType CYAN_BANNER = get("minecraft:cyan_banner"); + @Nullable public static final ItemType CYAN_BED = get("minecraft:cyan_bed"); + @Nullable public static final ItemType CYAN_CANDLE = get("minecraft:cyan_candle"); + @Nullable public static final ItemType CYAN_CARPET = get("minecraft:cyan_carpet"); + @Nullable public static final ItemType CYAN_CONCRETE = get("minecraft:cyan_concrete"); + @Nullable public static final ItemType CYAN_CONCRETE_POWDER = get("minecraft:cyan_concrete_powder"); + @Nullable public static final ItemType CYAN_DYE = get("minecraft:cyan_dye"); + @Nullable public static final ItemType CYAN_GLAZED_TERRACOTTA = get("minecraft:cyan_glazed_terracotta"); + @Nullable public static final ItemType CYAN_SHULKER_BOX = get("minecraft:cyan_shulker_box"); + @Nullable public static final ItemType CYAN_STAINED_GLASS = get("minecraft:cyan_stained_glass"); + @Nullable public static final ItemType CYAN_STAINED_GLASS_PANE = get("minecraft:cyan_stained_glass_pane"); + @Nullable public static final ItemType CYAN_TERRACOTTA = get("minecraft:cyan_terracotta"); + @Nullable public static final ItemType CYAN_WOOL = get("minecraft:cyan_wool"); + @Nullable public static final ItemType DAMAGED_ANVIL = get("minecraft:damaged_anvil"); + @Nullable public static final ItemType DANDELION = get("minecraft:dandelion"); + @Deprecated @Nullable public static final ItemType DANDELION_YELLOW = get("minecraft:dandelion_yellow"); + @Nullable public static final ItemType DANGER_POTTERY_SHERD = get("minecraft:danger_pottery_sherd"); + @Nullable public static final ItemType DARK_OAK_BOAT = get("minecraft:dark_oak_boat"); + @Nullable public static final ItemType DARK_OAK_BUTTON = get("minecraft:dark_oak_button"); + @Nullable public static final ItemType DARK_OAK_CHEST_BOAT = get("minecraft:dark_oak_chest_boat"); + @Nullable public static final ItemType DARK_OAK_DOOR = get("minecraft:dark_oak_door"); + @Nullable public static final ItemType DARK_OAK_FENCE = get("minecraft:dark_oak_fence"); + @Nullable public static final ItemType DARK_OAK_FENCE_GATE = get("minecraft:dark_oak_fence_gate"); + @Nullable public static final ItemType DARK_OAK_HANGING_SIGN = get("minecraft:dark_oak_hanging_sign"); + @Nullable public static final ItemType DARK_OAK_LEAVES = get("minecraft:dark_oak_leaves"); + @Nullable public static final ItemType DARK_OAK_LOG = get("minecraft:dark_oak_log"); + @Nullable public static final ItemType DARK_OAK_PLANKS = get("minecraft:dark_oak_planks"); + @Nullable public static final ItemType DARK_OAK_PRESSURE_PLATE = get("minecraft:dark_oak_pressure_plate"); + @Nullable public static final ItemType DARK_OAK_SAPLING = get("minecraft:dark_oak_sapling"); + @Nullable public static final ItemType DARK_OAK_SIGN = get("minecraft:dark_oak_sign"); + @Nullable public static final ItemType DARK_OAK_SLAB = get("minecraft:dark_oak_slab"); + @Nullable public static final ItemType DARK_OAK_STAIRS = get("minecraft:dark_oak_stairs"); + @Nullable public static final ItemType DARK_OAK_TRAPDOOR = get("minecraft:dark_oak_trapdoor"); + @Nullable public static final ItemType DARK_OAK_WOOD = get("minecraft:dark_oak_wood"); + @Nullable public static final ItemType DARK_PRISMARINE = get("minecraft:dark_prismarine"); + @Nullable public static final ItemType DARK_PRISMARINE_SLAB = get("minecraft:dark_prismarine_slab"); + @Nullable public static final ItemType DARK_PRISMARINE_STAIRS = get("minecraft:dark_prismarine_stairs"); + @Nullable public static final ItemType DAYLIGHT_DETECTOR = get("minecraft:daylight_detector"); + @Nullable public static final ItemType DEAD_BRAIN_CORAL = get("minecraft:dead_brain_coral"); + @Nullable public static final ItemType DEAD_BRAIN_CORAL_BLOCK = get("minecraft:dead_brain_coral_block"); + @Nullable public static final ItemType DEAD_BRAIN_CORAL_FAN = get("minecraft:dead_brain_coral_fan"); + @Nullable public static final ItemType DEAD_BUBBLE_CORAL = get("minecraft:dead_bubble_coral"); + @Nullable public static final ItemType DEAD_BUBBLE_CORAL_BLOCK = get("minecraft:dead_bubble_coral_block"); + @Nullable public static final ItemType DEAD_BUBBLE_CORAL_FAN = get("minecraft:dead_bubble_coral_fan"); + @Nullable public static final ItemType DEAD_BUSH = get("minecraft:dead_bush"); + @Nullable public static final ItemType DEAD_FIRE_CORAL = get("minecraft:dead_fire_coral"); + @Nullable public static final ItemType DEAD_FIRE_CORAL_BLOCK = get("minecraft:dead_fire_coral_block"); + @Nullable public static final ItemType DEAD_FIRE_CORAL_FAN = get("minecraft:dead_fire_coral_fan"); + @Nullable public static final ItemType DEAD_HORN_CORAL = get("minecraft:dead_horn_coral"); + @Nullable public static final ItemType DEAD_HORN_CORAL_BLOCK = get("minecraft:dead_horn_coral_block"); + @Nullable public static final ItemType DEAD_HORN_CORAL_FAN = get("minecraft:dead_horn_coral_fan"); + @Nullable public static final ItemType DEAD_TUBE_CORAL = get("minecraft:dead_tube_coral"); + @Nullable public static final ItemType DEAD_TUBE_CORAL_BLOCK = get("minecraft:dead_tube_coral_block"); + @Nullable public static final ItemType DEAD_TUBE_CORAL_FAN = get("minecraft:dead_tube_coral_fan"); + @Nullable public static final ItemType DEBUG_STICK = get("minecraft:debug_stick"); + @Nullable public static final ItemType DECORATED_POT = get("minecraft:decorated_pot"); + @Nullable public static final ItemType DEEPSLATE = get("minecraft:deepslate"); + @Nullable public static final ItemType DEEPSLATE_BRICK_SLAB = get("minecraft:deepslate_brick_slab"); + @Nullable public static final ItemType DEEPSLATE_BRICK_STAIRS = get("minecraft:deepslate_brick_stairs"); + @Nullable public static final ItemType DEEPSLATE_BRICK_WALL = get("minecraft:deepslate_brick_wall"); + @Nullable public static final ItemType DEEPSLATE_BRICKS = get("minecraft:deepslate_bricks"); + @Nullable public static final ItemType DEEPSLATE_COAL_ORE = get("minecraft:deepslate_coal_ore"); + @Nullable public static final ItemType DEEPSLATE_COPPER_ORE = get("minecraft:deepslate_copper_ore"); + @Nullable public static final ItemType DEEPSLATE_DIAMOND_ORE = get("minecraft:deepslate_diamond_ore"); + @Nullable public static final ItemType DEEPSLATE_EMERALD_ORE = get("minecraft:deepslate_emerald_ore"); + @Nullable public static final ItemType DEEPSLATE_GOLD_ORE = get("minecraft:deepslate_gold_ore"); + @Nullable public static final ItemType DEEPSLATE_IRON_ORE = get("minecraft:deepslate_iron_ore"); + @Nullable public static final ItemType DEEPSLATE_LAPIS_ORE = get("minecraft:deepslate_lapis_ore"); + @Nullable public static final ItemType DEEPSLATE_REDSTONE_ORE = get("minecraft:deepslate_redstone_ore"); + @Nullable public static final ItemType DEEPSLATE_TILE_SLAB = get("minecraft:deepslate_tile_slab"); + @Nullable public static final ItemType DEEPSLATE_TILE_STAIRS = get("minecraft:deepslate_tile_stairs"); + @Nullable public static final ItemType DEEPSLATE_TILE_WALL = get("minecraft:deepslate_tile_wall"); + @Nullable public static final ItemType DEEPSLATE_TILES = get("minecraft:deepslate_tiles"); + @Nullable public static final ItemType DETECTOR_RAIL = get("minecraft:detector_rail"); + @Nullable public static final ItemType DIAMOND = get("minecraft:diamond"); + @Nullable public static final ItemType DIAMOND_AXE = get("minecraft:diamond_axe"); + @Nullable public static final ItemType DIAMOND_BLOCK = get("minecraft:diamond_block"); + @Nullable public static final ItemType DIAMOND_BOOTS = get("minecraft:diamond_boots"); + @Nullable public static final ItemType DIAMOND_CHESTPLATE = get("minecraft:diamond_chestplate"); + @Nullable public static final ItemType DIAMOND_HELMET = get("minecraft:diamond_helmet"); + @Nullable public static final ItemType DIAMOND_HOE = get("minecraft:diamond_hoe"); + @Nullable public static final ItemType DIAMOND_HORSE_ARMOR = get("minecraft:diamond_horse_armor"); + @Nullable public static final ItemType DIAMOND_LEGGINGS = get("minecraft:diamond_leggings"); + @Nullable public static final ItemType DIAMOND_ORE = get("minecraft:diamond_ore"); + @Nullable public static final ItemType DIAMOND_PICKAXE = get("minecraft:diamond_pickaxe"); + @Nullable public static final ItemType DIAMOND_SHOVEL = get("minecraft:diamond_shovel"); + @Nullable public static final ItemType DIAMOND_SWORD = get("minecraft:diamond_sword"); + @Nullable public static final ItemType DIORITE = get("minecraft:diorite"); + @Nullable public static final ItemType DIORITE_SLAB = get("minecraft:diorite_slab"); + @Nullable public static final ItemType DIORITE_STAIRS = get("minecraft:diorite_stairs"); + @Nullable public static final ItemType DIORITE_WALL = get("minecraft:diorite_wall"); + @Nullable public static final ItemType DIRT = get("minecraft:dirt"); + @Nullable public static final ItemType DIRT_PATH = get("minecraft:dirt_path"); + @Nullable public static final ItemType DISC_FRAGMENT_5 = get("minecraft:disc_fragment_5"); + @Nullable public static final ItemType DISPENSER = get("minecraft:dispenser"); + @Nullable public static final ItemType DOLPHIN_SPAWN_EGG = get("minecraft:dolphin_spawn_egg"); + @Nullable public static final ItemType DONKEY_SPAWN_EGG = get("minecraft:donkey_spawn_egg"); + @Nullable public static final ItemType DRAGON_BREATH = get("minecraft:dragon_breath"); + @Nullable public static final ItemType DRAGON_EGG = get("minecraft:dragon_egg"); + @Nullable public static final ItemType DRAGON_HEAD = get("minecraft:dragon_head"); + @Nullable public static final ItemType DRIED_KELP = get("minecraft:dried_kelp"); + @Nullable public static final ItemType DRIED_KELP_BLOCK = get("minecraft:dried_kelp_block"); + @Nullable public static final ItemType DRIPSTONE_BLOCK = get("minecraft:dripstone_block"); + @Nullable public static final ItemType DROPPER = get("minecraft:dropper"); + @Nullable public static final ItemType DROWNED_SPAWN_EGG = get("minecraft:drowned_spawn_egg"); + @Nullable public static final ItemType DUNE_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:dune_armor_trim_smithing_template"); + @Nullable public static final ItemType ECHO_SHARD = get("minecraft:echo_shard"); + @Nullable public static final ItemType EGG = get("minecraft:egg"); + @Nullable public static final ItemType ELDER_GUARDIAN_SPAWN_EGG = get("minecraft:elder_guardian_spawn_egg"); + @Nullable public static final ItemType ELYTRA = get("minecraft:elytra"); + @Nullable public static final ItemType EMERALD = get("minecraft:emerald"); + @Nullable public static final ItemType EMERALD_BLOCK = get("minecraft:emerald_block"); + @Nullable public static final ItemType EMERALD_ORE = get("minecraft:emerald_ore"); + @Nullable public static final ItemType ENCHANTED_BOOK = get("minecraft:enchanted_book"); + @Nullable public static final ItemType ENCHANTED_GOLDEN_APPLE = get("minecraft:enchanted_golden_apple"); + @Nullable public static final ItemType ENCHANTING_TABLE = get("minecraft:enchanting_table"); + @Nullable public static final ItemType END_CRYSTAL = get("minecraft:end_crystal"); + @Nullable public static final ItemType END_PORTAL_FRAME = get("minecraft:end_portal_frame"); + @Nullable public static final ItemType END_ROD = get("minecraft:end_rod"); + @Nullable public static final ItemType END_STONE = get("minecraft:end_stone"); + @Nullable public static final ItemType END_STONE_BRICK_SLAB = get("minecraft:end_stone_brick_slab"); + @Nullable public static final ItemType END_STONE_BRICK_STAIRS = get("minecraft:end_stone_brick_stairs"); + @Nullable public static final ItemType END_STONE_BRICK_WALL = get("minecraft:end_stone_brick_wall"); + @Nullable public static final ItemType END_STONE_BRICKS = get("minecraft:end_stone_bricks"); + @Nullable public static final ItemType ENDER_CHEST = get("minecraft:ender_chest"); + @Nullable public static final ItemType ENDER_DRAGON_SPAWN_EGG = get("minecraft:ender_dragon_spawn_egg"); + @Nullable public static final ItemType ENDER_EYE = get("minecraft:ender_eye"); + @Nullable public static final ItemType ENDER_PEARL = get("minecraft:ender_pearl"); + @Nullable public static final ItemType ENDERMAN_SPAWN_EGG = get("minecraft:enderman_spawn_egg"); + @Nullable public static final ItemType ENDERMITE_SPAWN_EGG = get("minecraft:endermite_spawn_egg"); + @Nullable public static final ItemType EVOKER_SPAWN_EGG = get("minecraft:evoker_spawn_egg"); + @Nullable public static final ItemType EXPERIENCE_BOTTLE = get("minecraft:experience_bottle"); + @Nullable public static final ItemType EXPLORER_POTTERY_SHERD = get("minecraft:explorer_pottery_sherd"); + @Nullable public static final ItemType EXPOSED_COPPER = get("minecraft:exposed_copper"); + @Nullable public static final ItemType EXPOSED_CUT_COPPER = get("minecraft:exposed_cut_copper"); + @Nullable public static final ItemType EXPOSED_CUT_COPPER_SLAB = get("minecraft:exposed_cut_copper_slab"); + @Nullable public static final ItemType EXPOSED_CUT_COPPER_STAIRS = get("minecraft:exposed_cut_copper_stairs"); + @Nullable public static final ItemType EYE_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:eye_armor_trim_smithing_template"); + @Nullable public static final ItemType FARMLAND = get("minecraft:farmland"); + @Nullable public static final ItemType FEATHER = get("minecraft:feather"); + @Nullable public static final ItemType FERMENTED_SPIDER_EYE = get("minecraft:fermented_spider_eye"); + @Nullable public static final ItemType FERN = get("minecraft:fern"); + @Nullable public static final ItemType FILLED_MAP = get("minecraft:filled_map"); + @Nullable public static final ItemType FIRE_CHARGE = get("minecraft:fire_charge"); + @Nullable public static final ItemType FIRE_CORAL = get("minecraft:fire_coral"); + @Nullable public static final ItemType FIRE_CORAL_BLOCK = get("minecraft:fire_coral_block"); + @Nullable public static final ItemType FIRE_CORAL_FAN = get("minecraft:fire_coral_fan"); + @Nullable public static final ItemType FIREWORK_ROCKET = get("minecraft:firework_rocket"); + @Nullable public static final ItemType FIREWORK_STAR = get("minecraft:firework_star"); + @Nullable public static final ItemType FISHING_ROD = get("minecraft:fishing_rod"); + @Nullable public static final ItemType FLETCHING_TABLE = get("minecraft:fletching_table"); + @Nullable public static final ItemType FLINT = get("minecraft:flint"); + @Nullable public static final ItemType FLINT_AND_STEEL = get("minecraft:flint_and_steel"); + @Nullable public static final ItemType FLOWER_BANNER_PATTERN = get("minecraft:flower_banner_pattern"); + @Nullable public static final ItemType FLOWER_POT = get("minecraft:flower_pot"); + @Nullable public static final ItemType FLOWERING_AZALEA = get("minecraft:flowering_azalea"); + @Nullable public static final ItemType FLOWERING_AZALEA_LEAVES = get("minecraft:flowering_azalea_leaves"); + @Nullable public static final ItemType FOX_SPAWN_EGG = get("minecraft:fox_spawn_egg"); + @Nullable public static final ItemType FRIEND_POTTERY_SHERD = get("minecraft:friend_pottery_sherd"); + @Nullable public static final ItemType FROG_SPAWN_EGG = get("minecraft:frog_spawn_egg"); + @Nullable public static final ItemType FROGSPAWN = get("minecraft:frogspawn"); + @Nullable public static final ItemType FURNACE = get("minecraft:furnace"); + @Nullable public static final ItemType FURNACE_MINECART = get("minecraft:furnace_minecart"); + @Nullable public static final ItemType GHAST_SPAWN_EGG = get("minecraft:ghast_spawn_egg"); + @Nullable public static final ItemType GHAST_TEAR = get("minecraft:ghast_tear"); + @Nullable public static final ItemType GILDED_BLACKSTONE = get("minecraft:gilded_blackstone"); + @Nullable public static final ItemType GLASS = get("minecraft:glass"); + @Nullable public static final ItemType GLASS_BOTTLE = get("minecraft:glass_bottle"); + @Nullable public static final ItemType GLASS_PANE = get("minecraft:glass_pane"); + @Nullable public static final ItemType GLISTERING_MELON_SLICE = get("minecraft:glistering_melon_slice"); + @Nullable public static final ItemType GLOBE_BANNER_PATTERN = get("minecraft:globe_banner_pattern"); + @Nullable public static final ItemType GLOW_BERRIES = get("minecraft:glow_berries"); + @Nullable public static final ItemType GLOW_INK_SAC = get("minecraft:glow_ink_sac"); + @Nullable public static final ItemType GLOW_ITEM_FRAME = get("minecraft:glow_item_frame"); + @Nullable public static final ItemType GLOW_LICHEN = get("minecraft:glow_lichen"); + @Nullable public static final ItemType GLOW_SQUID_SPAWN_EGG = get("minecraft:glow_squid_spawn_egg"); + @Nullable public static final ItemType GLOWSTONE = get("minecraft:glowstone"); + @Nullable public static final ItemType GLOWSTONE_DUST = get("minecraft:glowstone_dust"); + @Nullable public static final ItemType GOAT_HORN = get("minecraft:goat_horn"); + @Nullable public static final ItemType GOAT_SPAWN_EGG = get("minecraft:goat_spawn_egg"); + @Nullable public static final ItemType GOLD_BLOCK = get("minecraft:gold_block"); + @Nullable public static final ItemType GOLD_INGOT = get("minecraft:gold_ingot"); + @Nullable public static final ItemType GOLD_NUGGET = get("minecraft:gold_nugget"); + @Nullable public static final ItemType GOLD_ORE = get("minecraft:gold_ore"); + @Nullable public static final ItemType GOLDEN_APPLE = get("minecraft:golden_apple"); + @Nullable public static final ItemType GOLDEN_AXE = get("minecraft:golden_axe"); + @Nullable public static final ItemType GOLDEN_BOOTS = get("minecraft:golden_boots"); + @Nullable public static final ItemType GOLDEN_CARROT = get("minecraft:golden_carrot"); + @Nullable public static final ItemType GOLDEN_CHESTPLATE = get("minecraft:golden_chestplate"); + @Nullable public static final ItemType GOLDEN_HELMET = get("minecraft:golden_helmet"); + @Nullable public static final ItemType GOLDEN_HOE = get("minecraft:golden_hoe"); + @Nullable public static final ItemType GOLDEN_HORSE_ARMOR = get("minecraft:golden_horse_armor"); + @Nullable public static final ItemType GOLDEN_LEGGINGS = get("minecraft:golden_leggings"); + @Nullable public static final ItemType GOLDEN_PICKAXE = get("minecraft:golden_pickaxe"); + @Nullable public static final ItemType GOLDEN_SHOVEL = get("minecraft:golden_shovel"); + @Nullable public static final ItemType GOLDEN_SWORD = get("minecraft:golden_sword"); + @Nullable public static final ItemType GRANITE = get("minecraft:granite"); + @Nullable public static final ItemType GRANITE_SLAB = get("minecraft:granite_slab"); + @Nullable public static final ItemType GRANITE_STAIRS = get("minecraft:granite_stairs"); + @Nullable public static final ItemType GRANITE_WALL = get("minecraft:granite_wall"); + @Nullable public static final ItemType GRASS = get("minecraft:grass"); + @Nullable public static final ItemType GRASS_BLOCK = get("minecraft:grass_block"); + @Deprecated @Nullable public static final ItemType GRASS_PATH = get("minecraft:grass_path"); + @Nullable public static final ItemType GRAVEL = get("minecraft:gravel"); + @Nullable public static final ItemType GRAY_BANNER = get("minecraft:gray_banner"); + @Nullable public static final ItemType GRAY_BED = get("minecraft:gray_bed"); + @Nullable public static final ItemType GRAY_CANDLE = get("minecraft:gray_candle"); + @Nullable public static final ItemType GRAY_CARPET = get("minecraft:gray_carpet"); + @Nullable public static final ItemType GRAY_CONCRETE = get("minecraft:gray_concrete"); + @Nullable public static final ItemType GRAY_CONCRETE_POWDER = get("minecraft:gray_concrete_powder"); + @Nullable public static final ItemType GRAY_DYE = get("minecraft:gray_dye"); + @Nullable public static final ItemType GRAY_GLAZED_TERRACOTTA = get("minecraft:gray_glazed_terracotta"); + @Nullable public static final ItemType GRAY_SHULKER_BOX = get("minecraft:gray_shulker_box"); + @Nullable public static final ItemType GRAY_STAINED_GLASS = get("minecraft:gray_stained_glass"); + @Nullable public static final ItemType GRAY_STAINED_GLASS_PANE = get("minecraft:gray_stained_glass_pane"); + @Nullable public static final ItemType GRAY_TERRACOTTA = get("minecraft:gray_terracotta"); + @Nullable public static final ItemType GRAY_WOOL = get("minecraft:gray_wool"); + @Nullable public static final ItemType GREEN_BANNER = get("minecraft:green_banner"); + @Nullable public static final ItemType GREEN_BED = get("minecraft:green_bed"); + @Nullable public static final ItemType GREEN_CANDLE = get("minecraft:green_candle"); + @Nullable public static final ItemType GREEN_CARPET = get("minecraft:green_carpet"); + @Nullable public static final ItemType GREEN_CONCRETE = get("minecraft:green_concrete"); + @Nullable public static final ItemType GREEN_CONCRETE_POWDER = get("minecraft:green_concrete_powder"); + @Nullable public static final ItemType GREEN_DYE = get("minecraft:green_dye"); + @Nullable public static final ItemType GREEN_GLAZED_TERRACOTTA = get("minecraft:green_glazed_terracotta"); + @Nullable public static final ItemType GREEN_SHULKER_BOX = get("minecraft:green_shulker_box"); + @Nullable public static final ItemType GREEN_STAINED_GLASS = get("minecraft:green_stained_glass"); + @Nullable public static final ItemType GREEN_STAINED_GLASS_PANE = get("minecraft:green_stained_glass_pane"); + @Nullable public static final ItemType GREEN_TERRACOTTA = get("minecraft:green_terracotta"); + @Nullable public static final ItemType GREEN_WOOL = get("minecraft:green_wool"); + @Nullable public static final ItemType GRINDSTONE = get("minecraft:grindstone"); + @Nullable public static final ItemType GUARDIAN_SPAWN_EGG = get("minecraft:guardian_spawn_egg"); + @Nullable public static final ItemType GUNPOWDER = get("minecraft:gunpowder"); + @Nullable public static final ItemType HANGING_ROOTS = get("minecraft:hanging_roots"); + @Nullable public static final ItemType HAY_BLOCK = get("minecraft:hay_block"); + @Nullable public static final ItemType HEART_OF_THE_SEA = get("minecraft:heart_of_the_sea"); + @Nullable public static final ItemType HEART_POTTERY_SHERD = get("minecraft:heart_pottery_sherd"); + @Nullable public static final ItemType HEARTBREAK_POTTERY_SHERD = get("minecraft:heartbreak_pottery_sherd"); + @Nullable public static final ItemType HEAVY_WEIGHTED_PRESSURE_PLATE = get("minecraft:heavy_weighted_pressure_plate"); + @Nullable public static final ItemType HOGLIN_SPAWN_EGG = get("minecraft:hoglin_spawn_egg"); + @Nullable public static final ItemType HONEY_BLOCK = get("minecraft:honey_block"); + @Nullable public static final ItemType HONEY_BOTTLE = get("minecraft:honey_bottle"); + @Nullable public static final ItemType HONEYCOMB = get("minecraft:honeycomb"); + @Nullable public static final ItemType HONEYCOMB_BLOCK = get("minecraft:honeycomb_block"); + @Nullable public static final ItemType HOPPER = get("minecraft:hopper"); + @Nullable public static final ItemType HOPPER_MINECART = get("minecraft:hopper_minecart"); + @Nullable public static final ItemType HORN_CORAL = get("minecraft:horn_coral"); + @Nullable public static final ItemType HORN_CORAL_BLOCK = get("minecraft:horn_coral_block"); + @Nullable public static final ItemType HORN_CORAL_FAN = get("minecraft:horn_coral_fan"); + @Nullable public static final ItemType HORSE_SPAWN_EGG = get("minecraft:horse_spawn_egg"); + @Nullable public static final ItemType HOST_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:host_armor_trim_smithing_template"); + @Nullable public static final ItemType HOWL_POTTERY_SHERD = get("minecraft:howl_pottery_sherd"); + @Nullable public static final ItemType HUSK_SPAWN_EGG = get("minecraft:husk_spawn_egg"); + @Nullable public static final ItemType ICE = get("minecraft:ice"); + @Nullable public static final ItemType INFESTED_CHISELED_STONE_BRICKS = get("minecraft:infested_chiseled_stone_bricks"); + @Nullable public static final ItemType INFESTED_COBBLESTONE = get("minecraft:infested_cobblestone"); + @Nullable public static final ItemType INFESTED_CRACKED_STONE_BRICKS = get("minecraft:infested_cracked_stone_bricks"); + @Nullable public static final ItemType INFESTED_DEEPSLATE = get("minecraft:infested_deepslate"); + @Nullable public static final ItemType INFESTED_MOSSY_STONE_BRICKS = get("minecraft:infested_mossy_stone_bricks"); + @Nullable public static final ItemType INFESTED_STONE = get("minecraft:infested_stone"); + @Nullable public static final ItemType INFESTED_STONE_BRICKS = get("minecraft:infested_stone_bricks"); + @Nullable public static final ItemType INK_SAC = get("minecraft:ink_sac"); + @Nullable public static final ItemType IRON_AXE = get("minecraft:iron_axe"); + @Nullable public static final ItemType IRON_BARS = get("minecraft:iron_bars"); + @Nullable public static final ItemType IRON_BLOCK = get("minecraft:iron_block"); + @Nullable public static final ItemType IRON_BOOTS = get("minecraft:iron_boots"); + @Nullable public static final ItemType IRON_CHESTPLATE = get("minecraft:iron_chestplate"); + @Nullable public static final ItemType IRON_DOOR = get("minecraft:iron_door"); + @Nullable public static final ItemType IRON_GOLEM_SPAWN_EGG = get("minecraft:iron_golem_spawn_egg"); + @Nullable public static final ItemType IRON_HELMET = get("minecraft:iron_helmet"); + @Nullable public static final ItemType IRON_HOE = get("minecraft:iron_hoe"); + @Nullable public static final ItemType IRON_HORSE_ARMOR = get("minecraft:iron_horse_armor"); + @Nullable public static final ItemType IRON_INGOT = get("minecraft:iron_ingot"); + @Nullable public static final ItemType IRON_LEGGINGS = get("minecraft:iron_leggings"); + @Nullable public static final ItemType IRON_NUGGET = get("minecraft:iron_nugget"); + @Nullable public static final ItemType IRON_ORE = get("minecraft:iron_ore"); + @Nullable public static final ItemType IRON_PICKAXE = get("minecraft:iron_pickaxe"); + @Nullable public static final ItemType IRON_SHOVEL = get("minecraft:iron_shovel"); + @Nullable public static final ItemType IRON_SWORD = get("minecraft:iron_sword"); + @Nullable public static final ItemType IRON_TRAPDOOR = get("minecraft:iron_trapdoor"); + @Nullable public static final ItemType ITEM_FRAME = get("minecraft:item_frame"); + @Nullable public static final ItemType JACK_O_LANTERN = get("minecraft:jack_o_lantern"); + @Nullable public static final ItemType JIGSAW = get("minecraft:jigsaw"); + @Nullable public static final ItemType JUKEBOX = get("minecraft:jukebox"); + @Nullable public static final ItemType JUNGLE_BOAT = get("minecraft:jungle_boat"); + @Nullable public static final ItemType JUNGLE_BUTTON = get("minecraft:jungle_button"); + @Nullable public static final ItemType JUNGLE_CHEST_BOAT = get("minecraft:jungle_chest_boat"); + @Nullable public static final ItemType JUNGLE_DOOR = get("minecraft:jungle_door"); + @Nullable public static final ItemType JUNGLE_FENCE = get("minecraft:jungle_fence"); + @Nullable public static final ItemType JUNGLE_FENCE_GATE = get("minecraft:jungle_fence_gate"); + @Nullable public static final ItemType JUNGLE_HANGING_SIGN = get("minecraft:jungle_hanging_sign"); + @Nullable public static final ItemType JUNGLE_LEAVES = get("minecraft:jungle_leaves"); + @Nullable public static final ItemType JUNGLE_LOG = get("minecraft:jungle_log"); + @Nullable public static final ItemType JUNGLE_PLANKS = get("minecraft:jungle_planks"); + @Nullable public static final ItemType JUNGLE_PRESSURE_PLATE = get("minecraft:jungle_pressure_plate"); + @Nullable public static final ItemType JUNGLE_SAPLING = get("minecraft:jungle_sapling"); + @Nullable public static final ItemType JUNGLE_SIGN = get("minecraft:jungle_sign"); + @Nullable public static final ItemType JUNGLE_SLAB = get("minecraft:jungle_slab"); + @Nullable public static final ItemType JUNGLE_STAIRS = get("minecraft:jungle_stairs"); + @Nullable public static final ItemType JUNGLE_TRAPDOOR = get("minecraft:jungle_trapdoor"); + @Nullable public static final ItemType JUNGLE_WOOD = get("minecraft:jungle_wood"); + @Nullable public static final ItemType KELP = get("minecraft:kelp"); + @Nullable public static final ItemType KNOWLEDGE_BOOK = get("minecraft:knowledge_book"); + @Nullable public static final ItemType LADDER = get("minecraft:ladder"); + @Nullable public static final ItemType LANTERN = get("minecraft:lantern"); + @Nullable public static final ItemType LAPIS_BLOCK = get("minecraft:lapis_block"); + @Nullable public static final ItemType LAPIS_LAZULI = get("minecraft:lapis_lazuli"); + @Nullable public static final ItemType LAPIS_ORE = get("minecraft:lapis_ore"); + @Nullable public static final ItemType LARGE_AMETHYST_BUD = get("minecraft:large_amethyst_bud"); + @Nullable public static final ItemType LARGE_FERN = get("minecraft:large_fern"); + @Nullable public static final ItemType LAVA_BUCKET = get("minecraft:lava_bucket"); + @Nullable public static final ItemType LEAD = get("minecraft:lead"); + @Nullable public static final ItemType LEATHER = get("minecraft:leather"); + @Nullable public static final ItemType LEATHER_BOOTS = get("minecraft:leather_boots"); + @Nullable public static final ItemType LEATHER_CHESTPLATE = get("minecraft:leather_chestplate"); + @Nullable public static final ItemType LEATHER_HELMET = get("minecraft:leather_helmet"); + @Nullable public static final ItemType LEATHER_HORSE_ARMOR = get("minecraft:leather_horse_armor"); + @Nullable public static final ItemType LEATHER_LEGGINGS = get("minecraft:leather_leggings"); + @Nullable public static final ItemType LECTERN = get("minecraft:lectern"); + @Nullable public static final ItemType LEVER = get("minecraft:lever"); + @Nullable public static final ItemType LIGHT = get("minecraft:light"); + @Nullable public static final ItemType LIGHT_BLUE_BANNER = get("minecraft:light_blue_banner"); + @Nullable public static final ItemType LIGHT_BLUE_BED = get("minecraft:light_blue_bed"); + @Nullable public static final ItemType LIGHT_BLUE_CANDLE = get("minecraft:light_blue_candle"); + @Nullable public static final ItemType LIGHT_BLUE_CARPET = get("minecraft:light_blue_carpet"); + @Nullable public static final ItemType LIGHT_BLUE_CONCRETE = get("minecraft:light_blue_concrete"); + @Nullable public static final ItemType LIGHT_BLUE_CONCRETE_POWDER = get("minecraft:light_blue_concrete_powder"); + @Nullable public static final ItemType LIGHT_BLUE_DYE = get("minecraft:light_blue_dye"); + @Nullable public static final ItemType LIGHT_BLUE_GLAZED_TERRACOTTA = get("minecraft:light_blue_glazed_terracotta"); + @Nullable public static final ItemType LIGHT_BLUE_SHULKER_BOX = get("minecraft:light_blue_shulker_box"); + @Nullable public static final ItemType LIGHT_BLUE_STAINED_GLASS = get("minecraft:light_blue_stained_glass"); + @Nullable public static final ItemType LIGHT_BLUE_STAINED_GLASS_PANE = get("minecraft:light_blue_stained_glass_pane"); + @Nullable public static final ItemType LIGHT_BLUE_TERRACOTTA = get("minecraft:light_blue_terracotta"); + @Nullable public static final ItemType LIGHT_BLUE_WOOL = get("minecraft:light_blue_wool"); + @Nullable public static final ItemType LIGHT_GRAY_BANNER = get("minecraft:light_gray_banner"); + @Nullable public static final ItemType LIGHT_GRAY_BED = get("minecraft:light_gray_bed"); + @Nullable public static final ItemType LIGHT_GRAY_CANDLE = get("minecraft:light_gray_candle"); + @Nullable public static final ItemType LIGHT_GRAY_CARPET = get("minecraft:light_gray_carpet"); + @Nullable public static final ItemType LIGHT_GRAY_CONCRETE = get("minecraft:light_gray_concrete"); + @Nullable public static final ItemType LIGHT_GRAY_CONCRETE_POWDER = get("minecraft:light_gray_concrete_powder"); + @Nullable public static final ItemType LIGHT_GRAY_DYE = get("minecraft:light_gray_dye"); + @Nullable public static final ItemType LIGHT_GRAY_GLAZED_TERRACOTTA = get("minecraft:light_gray_glazed_terracotta"); + @Nullable public static final ItemType LIGHT_GRAY_SHULKER_BOX = get("minecraft:light_gray_shulker_box"); + @Nullable public static final ItemType LIGHT_GRAY_STAINED_GLASS = get("minecraft:light_gray_stained_glass"); + @Nullable public static final ItemType LIGHT_GRAY_STAINED_GLASS_PANE = get("minecraft:light_gray_stained_glass_pane"); + @Nullable public static final ItemType LIGHT_GRAY_TERRACOTTA = get("minecraft:light_gray_terracotta"); + @Nullable public static final ItemType LIGHT_GRAY_WOOL = get("minecraft:light_gray_wool"); + @Nullable public static final ItemType LIGHT_WEIGHTED_PRESSURE_PLATE = get("minecraft:light_weighted_pressure_plate"); + @Nullable public static final ItemType LIGHTNING_ROD = get("minecraft:lightning_rod"); + @Nullable public static final ItemType LILAC = get("minecraft:lilac"); + @Nullable public static final ItemType LILY_OF_THE_VALLEY = get("minecraft:lily_of_the_valley"); + @Nullable public static final ItemType LILY_PAD = get("minecraft:lily_pad"); + @Nullable public static final ItemType LIME_BANNER = get("minecraft:lime_banner"); + @Nullable public static final ItemType LIME_BED = get("minecraft:lime_bed"); + @Nullable public static final ItemType LIME_CANDLE = get("minecraft:lime_candle"); + @Nullable public static final ItemType LIME_CARPET = get("minecraft:lime_carpet"); + @Nullable public static final ItemType LIME_CONCRETE = get("minecraft:lime_concrete"); + @Nullable public static final ItemType LIME_CONCRETE_POWDER = get("minecraft:lime_concrete_powder"); + @Nullable public static final ItemType LIME_DYE = get("minecraft:lime_dye"); + @Nullable public static final ItemType LIME_GLAZED_TERRACOTTA = get("minecraft:lime_glazed_terracotta"); + @Nullable public static final ItemType LIME_SHULKER_BOX = get("minecraft:lime_shulker_box"); + @Nullable public static final ItemType LIME_STAINED_GLASS = get("minecraft:lime_stained_glass"); + @Nullable public static final ItemType LIME_STAINED_GLASS_PANE = get("minecraft:lime_stained_glass_pane"); + @Nullable public static final ItemType LIME_TERRACOTTA = get("minecraft:lime_terracotta"); + @Nullable public static final ItemType LIME_WOOL = get("minecraft:lime_wool"); + @Nullable public static final ItemType LINGERING_POTION = get("minecraft:lingering_potion"); + @Nullable public static final ItemType LLAMA_SPAWN_EGG = get("minecraft:llama_spawn_egg"); + @Nullable public static final ItemType LODESTONE = get("minecraft:lodestone"); + @Nullable public static final ItemType LOOM = get("minecraft:loom"); + @Nullable public static final ItemType MAGENTA_BANNER = get("minecraft:magenta_banner"); + @Nullable public static final ItemType MAGENTA_BED = get("minecraft:magenta_bed"); + @Nullable public static final ItemType MAGENTA_CANDLE = get("minecraft:magenta_candle"); + @Nullable public static final ItemType MAGENTA_CARPET = get("minecraft:magenta_carpet"); + @Nullable public static final ItemType MAGENTA_CONCRETE = get("minecraft:magenta_concrete"); + @Nullable public static final ItemType MAGENTA_CONCRETE_POWDER = get("minecraft:magenta_concrete_powder"); + @Nullable public static final ItemType MAGENTA_DYE = get("minecraft:magenta_dye"); + @Nullable public static final ItemType MAGENTA_GLAZED_TERRACOTTA = get("minecraft:magenta_glazed_terracotta"); + @Nullable public static final ItemType MAGENTA_SHULKER_BOX = get("minecraft:magenta_shulker_box"); + @Nullable public static final ItemType MAGENTA_STAINED_GLASS = get("minecraft:magenta_stained_glass"); + @Nullable public static final ItemType MAGENTA_STAINED_GLASS_PANE = get("minecraft:magenta_stained_glass_pane"); + @Nullable public static final ItemType MAGENTA_TERRACOTTA = get("minecraft:magenta_terracotta"); + @Nullable public static final ItemType MAGENTA_WOOL = get("minecraft:magenta_wool"); + @Nullable public static final ItemType MAGMA_BLOCK = get("minecraft:magma_block"); + @Nullable public static final ItemType MAGMA_CREAM = get("minecraft:magma_cream"); + @Nullable public static final ItemType MAGMA_CUBE_SPAWN_EGG = get("minecraft:magma_cube_spawn_egg"); + @Nullable public static final ItemType MANGROVE_BOAT = get("minecraft:mangrove_boat"); + @Nullable public static final ItemType MANGROVE_BUTTON = get("minecraft:mangrove_button"); + @Nullable public static final ItemType MANGROVE_CHEST_BOAT = get("minecraft:mangrove_chest_boat"); + @Nullable public static final ItemType MANGROVE_DOOR = get("minecraft:mangrove_door"); + @Nullable public static final ItemType MANGROVE_FENCE = get("minecraft:mangrove_fence"); + @Nullable public static final ItemType MANGROVE_FENCE_GATE = get("minecraft:mangrove_fence_gate"); + @Nullable public static final ItemType MANGROVE_HANGING_SIGN = get("minecraft:mangrove_hanging_sign"); + @Nullable public static final ItemType MANGROVE_LEAVES = get("minecraft:mangrove_leaves"); + @Nullable public static final ItemType MANGROVE_LOG = get("minecraft:mangrove_log"); + @Nullable public static final ItemType MANGROVE_PLANKS = get("minecraft:mangrove_planks"); + @Nullable public static final ItemType MANGROVE_PRESSURE_PLATE = get("minecraft:mangrove_pressure_plate"); + @Nullable public static final ItemType MANGROVE_PROPAGULE = get("minecraft:mangrove_propagule"); + @Nullable public static final ItemType MANGROVE_ROOTS = get("minecraft:mangrove_roots"); + @Nullable public static final ItemType MANGROVE_SIGN = get("minecraft:mangrove_sign"); + @Nullable public static final ItemType MANGROVE_SLAB = get("minecraft:mangrove_slab"); + @Nullable public static final ItemType MANGROVE_STAIRS = get("minecraft:mangrove_stairs"); + @Nullable public static final ItemType MANGROVE_TRAPDOOR = get("minecraft:mangrove_trapdoor"); + @Nullable public static final ItemType MANGROVE_WOOD = get("minecraft:mangrove_wood"); + @Nullable public static final ItemType MAP = get("minecraft:map"); + @Nullable public static final ItemType MEDIUM_AMETHYST_BUD = get("minecraft:medium_amethyst_bud"); + @Nullable public static final ItemType MELON = get("minecraft:melon"); + @Nullable public static final ItemType MELON_SEEDS = get("minecraft:melon_seeds"); + @Nullable public static final ItemType MELON_SLICE = get("minecraft:melon_slice"); + @Nullable public static final ItemType MILK_BUCKET = get("minecraft:milk_bucket"); + @Nullable public static final ItemType MINECART = get("minecraft:minecart"); + @Nullable public static final ItemType MINER_POTTERY_SHERD = get("minecraft:miner_pottery_sherd"); + @Nullable public static final ItemType MOJANG_BANNER_PATTERN = get("minecraft:mojang_banner_pattern"); + @Nullable public static final ItemType MOOSHROOM_SPAWN_EGG = get("minecraft:mooshroom_spawn_egg"); + @Nullable public static final ItemType MOSS_BLOCK = get("minecraft:moss_block"); + @Nullable public static final ItemType MOSS_CARPET = get("minecraft:moss_carpet"); + @Nullable public static final ItemType MOSSY_COBBLESTONE = get("minecraft:mossy_cobblestone"); + @Nullable public static final ItemType MOSSY_COBBLESTONE_SLAB = get("minecraft:mossy_cobblestone_slab"); + @Nullable public static final ItemType MOSSY_COBBLESTONE_STAIRS = get("minecraft:mossy_cobblestone_stairs"); + @Nullable public static final ItemType MOSSY_COBBLESTONE_WALL = get("minecraft:mossy_cobblestone_wall"); + @Nullable public static final ItemType MOSSY_STONE_BRICK_SLAB = get("minecraft:mossy_stone_brick_slab"); + @Nullable public static final ItemType MOSSY_STONE_BRICK_STAIRS = get("minecraft:mossy_stone_brick_stairs"); + @Nullable public static final ItemType MOSSY_STONE_BRICK_WALL = get("minecraft:mossy_stone_brick_wall"); + @Nullable public static final ItemType MOSSY_STONE_BRICKS = get("minecraft:mossy_stone_bricks"); + @Nullable public static final ItemType MOURNER_POTTERY_SHERD = get("minecraft:mourner_pottery_sherd"); + @Nullable public static final ItemType MUD = get("minecraft:mud"); + @Nullable public static final ItemType MUD_BRICK_SLAB = get("minecraft:mud_brick_slab"); + @Nullable public static final ItemType MUD_BRICK_STAIRS = get("minecraft:mud_brick_stairs"); + @Nullable public static final ItemType MUD_BRICK_WALL = get("minecraft:mud_brick_wall"); + @Nullable public static final ItemType MUD_BRICKS = get("minecraft:mud_bricks"); + @Nullable public static final ItemType MUDDY_MANGROVE_ROOTS = get("minecraft:muddy_mangrove_roots"); + @Nullable public static final ItemType MULE_SPAWN_EGG = get("minecraft:mule_spawn_egg"); + @Nullable public static final ItemType MUSHROOM_STEM = get("minecraft:mushroom_stem"); + @Nullable public static final ItemType MUSHROOM_STEW = get("minecraft:mushroom_stew"); + @Nullable public static final ItemType MUSIC_DISC_11 = get("minecraft:music_disc_11"); + @Nullable public static final ItemType MUSIC_DISC_13 = get("minecraft:music_disc_13"); + @Nullable public static final ItemType MUSIC_DISC_5 = get("minecraft:music_disc_5"); + @Nullable public static final ItemType MUSIC_DISC_BLOCKS = get("minecraft:music_disc_blocks"); + @Nullable public static final ItemType MUSIC_DISC_CAT = get("minecraft:music_disc_cat"); + @Nullable public static final ItemType MUSIC_DISC_CHIRP = get("minecraft:music_disc_chirp"); + @Nullable public static final ItemType MUSIC_DISC_FAR = get("minecraft:music_disc_far"); + @Nullable public static final ItemType MUSIC_DISC_MALL = get("minecraft:music_disc_mall"); + @Nullable public static final ItemType MUSIC_DISC_MELLOHI = get("minecraft:music_disc_mellohi"); + @Nullable public static final ItemType MUSIC_DISC_OTHERSIDE = get("minecraft:music_disc_otherside"); + @Nullable public static final ItemType MUSIC_DISC_PIGSTEP = get("minecraft:music_disc_pigstep"); + @Nullable public static final ItemType MUSIC_DISC_RELIC = get("minecraft:music_disc_relic"); + @Nullable public static final ItemType MUSIC_DISC_STAL = get("minecraft:music_disc_stal"); + @Nullable public static final ItemType MUSIC_DISC_STRAD = get("minecraft:music_disc_strad"); + @Nullable public static final ItemType MUSIC_DISC_WAIT = get("minecraft:music_disc_wait"); + @Nullable public static final ItemType MUSIC_DISC_WARD = get("minecraft:music_disc_ward"); + @Nullable public static final ItemType MUTTON = get("minecraft:mutton"); + @Nullable public static final ItemType MYCELIUM = get("minecraft:mycelium"); + @Nullable public static final ItemType NAME_TAG = get("minecraft:name_tag"); + @Nullable public static final ItemType NAUTILUS_SHELL = get("minecraft:nautilus_shell"); + @Nullable public static final ItemType NETHER_BRICK = get("minecraft:nether_brick"); + @Nullable public static final ItemType NETHER_BRICK_FENCE = get("minecraft:nether_brick_fence"); + @Nullable public static final ItemType NETHER_BRICK_SLAB = get("minecraft:nether_brick_slab"); + @Nullable public static final ItemType NETHER_BRICK_STAIRS = get("minecraft:nether_brick_stairs"); + @Nullable public static final ItemType NETHER_BRICK_WALL = get("minecraft:nether_brick_wall"); + @Nullable public static final ItemType NETHER_BRICKS = get("minecraft:nether_bricks"); + @Nullable public static final ItemType NETHER_GOLD_ORE = get("minecraft:nether_gold_ore"); + @Nullable public static final ItemType NETHER_QUARTZ_ORE = get("minecraft:nether_quartz_ore"); + @Nullable public static final ItemType NETHER_SPROUTS = get("minecraft:nether_sprouts"); + @Nullable public static final ItemType NETHER_STAR = get("minecraft:nether_star"); + @Nullable public static final ItemType NETHER_WART = get("minecraft:nether_wart"); + @Nullable public static final ItemType NETHER_WART_BLOCK = get("minecraft:nether_wart_block"); + @Nullable public static final ItemType NETHERITE_AXE = get("minecraft:netherite_axe"); + @Nullable public static final ItemType NETHERITE_BLOCK = get("minecraft:netherite_block"); + @Nullable public static final ItemType NETHERITE_BOOTS = get("minecraft:netherite_boots"); + @Nullable public static final ItemType NETHERITE_CHESTPLATE = get("minecraft:netherite_chestplate"); + @Nullable public static final ItemType NETHERITE_HELMET = get("minecraft:netherite_helmet"); + @Nullable public static final ItemType NETHERITE_HOE = get("minecraft:netherite_hoe"); + @Nullable public static final ItemType NETHERITE_INGOT = get("minecraft:netherite_ingot"); + @Nullable public static final ItemType NETHERITE_LEGGINGS = get("minecraft:netherite_leggings"); + @Nullable public static final ItemType NETHERITE_PICKAXE = get("minecraft:netherite_pickaxe"); + @Nullable public static final ItemType NETHERITE_SCRAP = get("minecraft:netherite_scrap"); + @Nullable public static final ItemType NETHERITE_SHOVEL = get("minecraft:netherite_shovel"); + @Nullable public static final ItemType NETHERITE_SWORD = get("minecraft:netherite_sword"); + @Nullable public static final ItemType NETHERITE_UPGRADE_SMITHING_TEMPLATE = get("minecraft:netherite_upgrade_smithing_template"); + @Nullable public static final ItemType NETHERRACK = get("minecraft:netherrack"); + @Nullable public static final ItemType NOTE_BLOCK = get("minecraft:note_block"); + @Nullable public static final ItemType OAK_BOAT = get("minecraft:oak_boat"); + @Nullable public static final ItemType OAK_BUTTON = get("minecraft:oak_button"); + @Nullable public static final ItemType OAK_CHEST_BOAT = get("minecraft:oak_chest_boat"); + @Nullable public static final ItemType OAK_DOOR = get("minecraft:oak_door"); + @Nullable public static final ItemType OAK_FENCE = get("minecraft:oak_fence"); + @Nullable public static final ItemType OAK_FENCE_GATE = get("minecraft:oak_fence_gate"); + @Nullable public static final ItemType OAK_HANGING_SIGN = get("minecraft:oak_hanging_sign"); + @Nullable public static final ItemType OAK_LEAVES = get("minecraft:oak_leaves"); + @Nullable public static final ItemType OAK_LOG = get("minecraft:oak_log"); + @Nullable public static final ItemType OAK_PLANKS = get("minecraft:oak_planks"); + @Nullable public static final ItemType OAK_PRESSURE_PLATE = get("minecraft:oak_pressure_plate"); + @Nullable public static final ItemType OAK_SAPLING = get("minecraft:oak_sapling"); + @Nullable public static final ItemType OAK_SIGN = get("minecraft:oak_sign"); + @Nullable public static final ItemType OAK_SLAB = get("minecraft:oak_slab"); + @Nullable public static final ItemType OAK_STAIRS = get("minecraft:oak_stairs"); + @Nullable public static final ItemType OAK_TRAPDOOR = get("minecraft:oak_trapdoor"); + @Nullable public static final ItemType OAK_WOOD = get("minecraft:oak_wood"); + @Nullable public static final ItemType OBSERVER = get("minecraft:observer"); + @Nullable public static final ItemType OBSIDIAN = get("minecraft:obsidian"); + @Nullable public static final ItemType OCELOT_SPAWN_EGG = get("minecraft:ocelot_spawn_egg"); + @Nullable public static final ItemType OCHRE_FROGLIGHT = get("minecraft:ochre_froglight"); + @Nullable public static final ItemType ORANGE_BANNER = get("minecraft:orange_banner"); + @Nullable public static final ItemType ORANGE_BED = get("minecraft:orange_bed"); + @Nullable public static final ItemType ORANGE_CANDLE = get("minecraft:orange_candle"); + @Nullable public static final ItemType ORANGE_CARPET = get("minecraft:orange_carpet"); + @Nullable public static final ItemType ORANGE_CONCRETE = get("minecraft:orange_concrete"); + @Nullable public static final ItemType ORANGE_CONCRETE_POWDER = get("minecraft:orange_concrete_powder"); + @Nullable public static final ItemType ORANGE_DYE = get("minecraft:orange_dye"); + @Nullable public static final ItemType ORANGE_GLAZED_TERRACOTTA = get("minecraft:orange_glazed_terracotta"); + @Nullable public static final ItemType ORANGE_SHULKER_BOX = get("minecraft:orange_shulker_box"); + @Nullable public static final ItemType ORANGE_STAINED_GLASS = get("minecraft:orange_stained_glass"); + @Nullable public static final ItemType ORANGE_STAINED_GLASS_PANE = get("minecraft:orange_stained_glass_pane"); + @Nullable public static final ItemType ORANGE_TERRACOTTA = get("minecraft:orange_terracotta"); + @Nullable public static final ItemType ORANGE_TULIP = get("minecraft:orange_tulip"); + @Nullable public static final ItemType ORANGE_WOOL = get("minecraft:orange_wool"); + @Nullable public static final ItemType OXEYE_DAISY = get("minecraft:oxeye_daisy"); + @Nullable public static final ItemType OXIDIZED_COPPER = get("minecraft:oxidized_copper"); + @Nullable public static final ItemType OXIDIZED_CUT_COPPER = get("minecraft:oxidized_cut_copper"); + @Nullable public static final ItemType OXIDIZED_CUT_COPPER_SLAB = get("minecraft:oxidized_cut_copper_slab"); + @Nullable public static final ItemType OXIDIZED_CUT_COPPER_STAIRS = get("minecraft:oxidized_cut_copper_stairs"); + @Nullable public static final ItemType PACKED_ICE = get("minecraft:packed_ice"); + @Nullable public static final ItemType PACKED_MUD = get("minecraft:packed_mud"); + @Nullable public static final ItemType PAINTING = get("minecraft:painting"); + @Nullable public static final ItemType PANDA_SPAWN_EGG = get("minecraft:panda_spawn_egg"); + @Nullable public static final ItemType PAPER = get("minecraft:paper"); + @Nullable public static final ItemType PARROT_SPAWN_EGG = get("minecraft:parrot_spawn_egg"); + @Nullable public static final ItemType PEARLESCENT_FROGLIGHT = get("minecraft:pearlescent_froglight"); + @Nullable public static final ItemType PEONY = get("minecraft:peony"); + @Nullable public static final ItemType PETRIFIED_OAK_SLAB = get("minecraft:petrified_oak_slab"); + @Nullable public static final ItemType PHANTOM_MEMBRANE = get("minecraft:phantom_membrane"); + @Nullable public static final ItemType PHANTOM_SPAWN_EGG = get("minecraft:phantom_spawn_egg"); + @Nullable public static final ItemType PIG_SPAWN_EGG = get("minecraft:pig_spawn_egg"); + @Nullable public static final ItemType PIGLIN_BANNER_PATTERN = get("minecraft:piglin_banner_pattern"); + @Nullable public static final ItemType PIGLIN_BRUTE_SPAWN_EGG = get("minecraft:piglin_brute_spawn_egg"); + @Nullable public static final ItemType PIGLIN_HEAD = get("minecraft:piglin_head"); + @Nullable public static final ItemType PIGLIN_SPAWN_EGG = get("minecraft:piglin_spawn_egg"); + @Nullable public static final ItemType PILLAGER_SPAWN_EGG = get("minecraft:pillager_spawn_egg"); + @Nullable public static final ItemType PINK_BANNER = get("minecraft:pink_banner"); + @Nullable public static final ItemType PINK_BED = get("minecraft:pink_bed"); + @Nullable public static final ItemType PINK_CANDLE = get("minecraft:pink_candle"); + @Nullable public static final ItemType PINK_CARPET = get("minecraft:pink_carpet"); + @Nullable public static final ItemType PINK_CONCRETE = get("minecraft:pink_concrete"); + @Nullable public static final ItemType PINK_CONCRETE_POWDER = get("minecraft:pink_concrete_powder"); + @Nullable public static final ItemType PINK_DYE = get("minecraft:pink_dye"); + @Nullable public static final ItemType PINK_GLAZED_TERRACOTTA = get("minecraft:pink_glazed_terracotta"); + @Nullable public static final ItemType PINK_PETALS = get("minecraft:pink_petals"); + @Nullable public static final ItemType PINK_SHULKER_BOX = get("minecraft:pink_shulker_box"); + @Nullable public static final ItemType PINK_STAINED_GLASS = get("minecraft:pink_stained_glass"); + @Nullable public static final ItemType PINK_STAINED_GLASS_PANE = get("minecraft:pink_stained_glass_pane"); + @Nullable public static final ItemType PINK_TERRACOTTA = get("minecraft:pink_terracotta"); + @Nullable public static final ItemType PINK_TULIP = get("minecraft:pink_tulip"); + @Nullable public static final ItemType PINK_WOOL = get("minecraft:pink_wool"); + @Nullable public static final ItemType PISTON = get("minecraft:piston"); + @Nullable public static final ItemType PITCHER_PLANT = get("minecraft:pitcher_plant"); + @Nullable public static final ItemType PITCHER_POD = get("minecraft:pitcher_pod"); + @Nullable public static final ItemType PLAYER_HEAD = get("minecraft:player_head"); + @Nullable public static final ItemType PLENTY_POTTERY_SHERD = get("minecraft:plenty_pottery_sherd"); + @Nullable public static final ItemType PODZOL = get("minecraft:podzol"); + @Nullable public static final ItemType POINTED_DRIPSTONE = get("minecraft:pointed_dripstone"); + @Nullable public static final ItemType POISONOUS_POTATO = get("minecraft:poisonous_potato"); + @Nullable public static final ItemType POLAR_BEAR_SPAWN_EGG = get("minecraft:polar_bear_spawn_egg"); + @Nullable public static final ItemType POLISHED_ANDESITE = get("minecraft:polished_andesite"); + @Nullable public static final ItemType POLISHED_ANDESITE_SLAB = get("minecraft:polished_andesite_slab"); + @Nullable public static final ItemType POLISHED_ANDESITE_STAIRS = get("minecraft:polished_andesite_stairs"); + @Nullable public static final ItemType POLISHED_BASALT = get("minecraft:polished_basalt"); + @Nullable public static final ItemType POLISHED_BLACKSTONE = get("minecraft:polished_blackstone"); + @Nullable public static final ItemType POLISHED_BLACKSTONE_BRICK_SLAB = get("minecraft:polished_blackstone_brick_slab"); + @Nullable public static final ItemType POLISHED_BLACKSTONE_BRICK_STAIRS = get("minecraft:polished_blackstone_brick_stairs"); + @Nullable public static final ItemType POLISHED_BLACKSTONE_BRICK_WALL = get("minecraft:polished_blackstone_brick_wall"); + @Nullable public static final ItemType POLISHED_BLACKSTONE_BRICKS = get("minecraft:polished_blackstone_bricks"); + @Nullable public static final ItemType POLISHED_BLACKSTONE_BUTTON = get("minecraft:polished_blackstone_button"); + @Nullable public static final ItemType POLISHED_BLACKSTONE_PRESSURE_PLATE = get("minecraft:polished_blackstone_pressure_plate"); + @Nullable public static final ItemType POLISHED_BLACKSTONE_SLAB = get("minecraft:polished_blackstone_slab"); + @Nullable public static final ItemType POLISHED_BLACKSTONE_STAIRS = get("minecraft:polished_blackstone_stairs"); + @Nullable public static final ItemType POLISHED_BLACKSTONE_WALL = get("minecraft:polished_blackstone_wall"); + @Nullable public static final ItemType POLISHED_DEEPSLATE = get("minecraft:polished_deepslate"); + @Nullable public static final ItemType POLISHED_DEEPSLATE_SLAB = get("minecraft:polished_deepslate_slab"); + @Nullable public static final ItemType POLISHED_DEEPSLATE_STAIRS = get("minecraft:polished_deepslate_stairs"); + @Nullable public static final ItemType POLISHED_DEEPSLATE_WALL = get("minecraft:polished_deepslate_wall"); + @Nullable public static final ItemType POLISHED_DIORITE = get("minecraft:polished_diorite"); + @Nullable public static final ItemType POLISHED_DIORITE_SLAB = get("minecraft:polished_diorite_slab"); + @Nullable public static final ItemType POLISHED_DIORITE_STAIRS = get("minecraft:polished_diorite_stairs"); + @Nullable public static final ItemType POLISHED_GRANITE = get("minecraft:polished_granite"); + @Nullable public static final ItemType POLISHED_GRANITE_SLAB = get("minecraft:polished_granite_slab"); + @Nullable public static final ItemType POLISHED_GRANITE_STAIRS = get("minecraft:polished_granite_stairs"); + @Nullable public static final ItemType POPPED_CHORUS_FRUIT = get("minecraft:popped_chorus_fruit"); + @Nullable public static final ItemType POPPY = get("minecraft:poppy"); + @Nullable public static final ItemType PORKCHOP = get("minecraft:porkchop"); + @Nullable public static final ItemType POTATO = get("minecraft:potato"); + @Nullable public static final ItemType POTION = get("minecraft:potion"); + @Nullable public static final ItemType POWDER_SNOW_BUCKET = get("minecraft:powder_snow_bucket"); + @Nullable public static final ItemType POWERED_RAIL = get("minecraft:powered_rail"); + @Nullable public static final ItemType PRISMARINE = get("minecraft:prismarine"); + @Nullable public static final ItemType PRISMARINE_BRICK_SLAB = get("minecraft:prismarine_brick_slab"); + @Nullable public static final ItemType PRISMARINE_BRICK_STAIRS = get("minecraft:prismarine_brick_stairs"); + @Nullable public static final ItemType PRISMARINE_BRICKS = get("minecraft:prismarine_bricks"); + @Nullable public static final ItemType PRISMARINE_CRYSTALS = get("minecraft:prismarine_crystals"); + @Nullable public static final ItemType PRISMARINE_SHARD = get("minecraft:prismarine_shard"); + @Nullable public static final ItemType PRISMARINE_SLAB = get("minecraft:prismarine_slab"); + @Nullable public static final ItemType PRISMARINE_STAIRS = get("minecraft:prismarine_stairs"); + @Nullable public static final ItemType PRISMARINE_WALL = get("minecraft:prismarine_wall"); + @Nullable public static final ItemType PRIZE_POTTERY_SHERD = get("minecraft:prize_pottery_sherd"); + @Nullable public static final ItemType PUFFERFISH = get("minecraft:pufferfish"); + @Nullable public static final ItemType PUFFERFISH_BUCKET = get("minecraft:pufferfish_bucket"); + @Nullable public static final ItemType PUFFERFISH_SPAWN_EGG = get("minecraft:pufferfish_spawn_egg"); + @Nullable public static final ItemType PUMPKIN = get("minecraft:pumpkin"); + @Nullable public static final ItemType PUMPKIN_PIE = get("minecraft:pumpkin_pie"); + @Nullable public static final ItemType PUMPKIN_SEEDS = get("minecraft:pumpkin_seeds"); + @Nullable public static final ItemType PURPLE_BANNER = get("minecraft:purple_banner"); + @Nullable public static final ItemType PURPLE_BED = get("minecraft:purple_bed"); + @Nullable public static final ItemType PURPLE_CANDLE = get("minecraft:purple_candle"); + @Nullable public static final ItemType PURPLE_CARPET = get("minecraft:purple_carpet"); + @Nullable public static final ItemType PURPLE_CONCRETE = get("minecraft:purple_concrete"); + @Nullable public static final ItemType PURPLE_CONCRETE_POWDER = get("minecraft:purple_concrete_powder"); + @Nullable public static final ItemType PURPLE_DYE = get("minecraft:purple_dye"); + @Nullable public static final ItemType PURPLE_GLAZED_TERRACOTTA = get("minecraft:purple_glazed_terracotta"); + @Nullable public static final ItemType PURPLE_SHULKER_BOX = get("minecraft:purple_shulker_box"); + @Nullable public static final ItemType PURPLE_STAINED_GLASS = get("minecraft:purple_stained_glass"); + @Nullable public static final ItemType PURPLE_STAINED_GLASS_PANE = get("minecraft:purple_stained_glass_pane"); + @Nullable public static final ItemType PURPLE_TERRACOTTA = get("minecraft:purple_terracotta"); + @Nullable public static final ItemType PURPLE_WOOL = get("minecraft:purple_wool"); + @Nullable public static final ItemType PURPUR_BLOCK = get("minecraft:purpur_block"); + @Nullable public static final ItemType PURPUR_PILLAR = get("minecraft:purpur_pillar"); + @Nullable public static final ItemType PURPUR_SLAB = get("minecraft:purpur_slab"); + @Nullable public static final ItemType PURPUR_STAIRS = get("minecraft:purpur_stairs"); + @Nullable public static final ItemType QUARTZ = get("minecraft:quartz"); + @Nullable public static final ItemType QUARTZ_BLOCK = get("minecraft:quartz_block"); + @Nullable public static final ItemType QUARTZ_BRICKS = get("minecraft:quartz_bricks"); + @Nullable public static final ItemType QUARTZ_PILLAR = get("minecraft:quartz_pillar"); + @Nullable public static final ItemType QUARTZ_SLAB = get("minecraft:quartz_slab"); + @Nullable public static final ItemType QUARTZ_STAIRS = get("minecraft:quartz_stairs"); + @Nullable public static final ItemType RABBIT = get("minecraft:rabbit"); + @Nullable public static final ItemType RABBIT_FOOT = get("minecraft:rabbit_foot"); + @Nullable public static final ItemType RABBIT_HIDE = get("minecraft:rabbit_hide"); + @Nullable public static final ItemType RABBIT_SPAWN_EGG = get("minecraft:rabbit_spawn_egg"); + @Nullable public static final ItemType RABBIT_STEW = get("minecraft:rabbit_stew"); + @Nullable public static final ItemType RAIL = get("minecraft:rail"); + @Nullable public static final ItemType RAISER_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:raiser_armor_trim_smithing_template"); + @Nullable public static final ItemType RAVAGER_SPAWN_EGG = get("minecraft:ravager_spawn_egg"); + @Nullable public static final ItemType RAW_COPPER = get("minecraft:raw_copper"); + @Nullable public static final ItemType RAW_COPPER_BLOCK = get("minecraft:raw_copper_block"); + @Nullable public static final ItemType RAW_GOLD = get("minecraft:raw_gold"); + @Nullable public static final ItemType RAW_GOLD_BLOCK = get("minecraft:raw_gold_block"); + @Nullable public static final ItemType RAW_IRON = get("minecraft:raw_iron"); + @Nullable public static final ItemType RAW_IRON_BLOCK = get("minecraft:raw_iron_block"); + @Nullable public static final ItemType RECOVERY_COMPASS = get("minecraft:recovery_compass"); + @Nullable public static final ItemType RED_BANNER = get("minecraft:red_banner"); + @Nullable public static final ItemType RED_BED = get("minecraft:red_bed"); + @Nullable public static final ItemType RED_CANDLE = get("minecraft:red_candle"); + @Nullable public static final ItemType RED_CARPET = get("minecraft:red_carpet"); + @Nullable public static final ItemType RED_CONCRETE = get("minecraft:red_concrete"); + @Nullable public static final ItemType RED_CONCRETE_POWDER = get("minecraft:red_concrete_powder"); + @Nullable public static final ItemType RED_DYE = get("minecraft:red_dye"); + @Nullable public static final ItemType RED_GLAZED_TERRACOTTA = get("minecraft:red_glazed_terracotta"); + @Nullable public static final ItemType RED_MUSHROOM = get("minecraft:red_mushroom"); + @Nullable public static final ItemType RED_MUSHROOM_BLOCK = get("minecraft:red_mushroom_block"); + @Nullable public static final ItemType RED_NETHER_BRICK_SLAB = get("minecraft:red_nether_brick_slab"); + @Nullable public static final ItemType RED_NETHER_BRICK_STAIRS = get("minecraft:red_nether_brick_stairs"); + @Nullable public static final ItemType RED_NETHER_BRICK_WALL = get("minecraft:red_nether_brick_wall"); + @Nullable public static final ItemType RED_NETHER_BRICKS = get("minecraft:red_nether_bricks"); + @Nullable public static final ItemType RED_SAND = get("minecraft:red_sand"); + @Nullable public static final ItemType RED_SANDSTONE = get("minecraft:red_sandstone"); + @Nullable public static final ItemType RED_SANDSTONE_SLAB = get("minecraft:red_sandstone_slab"); + @Nullable public static final ItemType RED_SANDSTONE_STAIRS = get("minecraft:red_sandstone_stairs"); + @Nullable public static final ItemType RED_SANDSTONE_WALL = get("minecraft:red_sandstone_wall"); + @Nullable public static final ItemType RED_SHULKER_BOX = get("minecraft:red_shulker_box"); + @Nullable public static final ItemType RED_STAINED_GLASS = get("minecraft:red_stained_glass"); + @Nullable public static final ItemType RED_STAINED_GLASS_PANE = get("minecraft:red_stained_glass_pane"); + @Nullable public static final ItemType RED_TERRACOTTA = get("minecraft:red_terracotta"); + @Nullable public static final ItemType RED_TULIP = get("minecraft:red_tulip"); + @Nullable public static final ItemType RED_WOOL = get("minecraft:red_wool"); + @Nullable public static final ItemType REDSTONE = get("minecraft:redstone"); + @Nullable public static final ItemType REDSTONE_BLOCK = get("minecraft:redstone_block"); + @Nullable public static final ItemType REDSTONE_LAMP = get("minecraft:redstone_lamp"); + @Nullable public static final ItemType REDSTONE_ORE = get("minecraft:redstone_ore"); + @Nullable public static final ItemType REDSTONE_TORCH = get("minecraft:redstone_torch"); + @Nullable public static final ItemType REINFORCED_DEEPSLATE = get("minecraft:reinforced_deepslate"); + @Nullable public static final ItemType REPEATER = get("minecraft:repeater"); + @Nullable public static final ItemType REPEATING_COMMAND_BLOCK = get("minecraft:repeating_command_block"); + @Nullable public static final ItemType RESPAWN_ANCHOR = get("minecraft:respawn_anchor"); + @Nullable public static final ItemType RIB_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:rib_armor_trim_smithing_template"); + @Nullable public static final ItemType ROOTED_DIRT = get("minecraft:rooted_dirt"); + @Nullable public static final ItemType ROSE_BUSH = get("minecraft:rose_bush"); + @Deprecated @Nullable public static final ItemType ROSE_RED = get("minecraft:rose_red"); + @Nullable public static final ItemType ROTTEN_FLESH = get("minecraft:rotten_flesh"); + @Nullable public static final ItemType SADDLE = get("minecraft:saddle"); + @Nullable public static final ItemType SALMON = get("minecraft:salmon"); + @Nullable public static final ItemType SALMON_BUCKET = get("minecraft:salmon_bucket"); + @Nullable public static final ItemType SALMON_SPAWN_EGG = get("minecraft:salmon_spawn_egg"); + @Nullable public static final ItemType SAND = get("minecraft:sand"); + @Nullable public static final ItemType SANDSTONE = get("minecraft:sandstone"); + @Nullable public static final ItemType SANDSTONE_SLAB = get("minecraft:sandstone_slab"); + @Nullable public static final ItemType SANDSTONE_STAIRS = get("minecraft:sandstone_stairs"); + @Nullable public static final ItemType SANDSTONE_WALL = get("minecraft:sandstone_wall"); + @Nullable public static final ItemType SCAFFOLDING = get("minecraft:scaffolding"); + @Nullable public static final ItemType SCULK = get("minecraft:sculk"); + @Nullable public static final ItemType SCULK_CATALYST = get("minecraft:sculk_catalyst"); + @Nullable public static final ItemType SCULK_SENSOR = get("minecraft:sculk_sensor"); + @Nullable public static final ItemType SCULK_SHRIEKER = get("minecraft:sculk_shrieker"); + @Nullable public static final ItemType SCULK_VEIN = get("minecraft:sculk_vein"); + @Nullable public static final ItemType SCUTE = get("minecraft:scute"); + @Nullable public static final ItemType SEA_LANTERN = get("minecraft:sea_lantern"); + @Nullable public static final ItemType SEA_PICKLE = get("minecraft:sea_pickle"); + @Nullable public static final ItemType SEAGRASS = get("minecraft:seagrass"); + @Nullable public static final ItemType SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:sentry_armor_trim_smithing_template"); + @Nullable public static final ItemType SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:shaper_armor_trim_smithing_template"); + @Nullable public static final ItemType SHEAF_POTTERY_SHERD = get("minecraft:sheaf_pottery_sherd"); + @Nullable public static final ItemType SHEARS = get("minecraft:shears"); + @Nullable public static final ItemType SHEEP_SPAWN_EGG = get("minecraft:sheep_spawn_egg"); + @Nullable public static final ItemType SHELTER_POTTERY_SHERD = get("minecraft:shelter_pottery_sherd"); + @Nullable public static final ItemType SHIELD = get("minecraft:shield"); + @Nullable public static final ItemType SHROOMLIGHT = get("minecraft:shroomlight"); + @Nullable public static final ItemType SHULKER_BOX = get("minecraft:shulker_box"); + @Nullable public static final ItemType SHULKER_SHELL = get("minecraft:shulker_shell"); + @Nullable public static final ItemType SHULKER_SPAWN_EGG = get("minecraft:shulker_spawn_egg"); + @Deprecated @Nullable public static final ItemType SIGN = get("minecraft:sign"); + @Nullable public static final ItemType SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:silence_armor_trim_smithing_template"); + @Nullable public static final ItemType SILVERFISH_SPAWN_EGG = get("minecraft:silverfish_spawn_egg"); + @Nullable public static final ItemType SKELETON_HORSE_SPAWN_EGG = get("minecraft:skeleton_horse_spawn_egg"); + @Nullable public static final ItemType SKELETON_SKULL = get("minecraft:skeleton_skull"); + @Nullable public static final ItemType SKELETON_SPAWN_EGG = get("minecraft:skeleton_spawn_egg"); + @Nullable public static final ItemType SKULL_BANNER_PATTERN = get("minecraft:skull_banner_pattern"); + @Nullable public static final ItemType SKULL_POTTERY_SHERD = get("minecraft:skull_pottery_sherd"); + @Nullable public static final ItemType SLIME_BALL = get("minecraft:slime_ball"); + @Nullable public static final ItemType SLIME_BLOCK = get("minecraft:slime_block"); + @Nullable public static final ItemType SLIME_SPAWN_EGG = get("minecraft:slime_spawn_egg"); + @Nullable public static final ItemType SMALL_AMETHYST_BUD = get("minecraft:small_amethyst_bud"); + @Nullable public static final ItemType SMALL_DRIPLEAF = get("minecraft:small_dripleaf"); + @Nullable public static final ItemType SMITHING_TABLE = get("minecraft:smithing_table"); + @Nullable public static final ItemType SMOKER = get("minecraft:smoker"); + @Nullable public static final ItemType SMOOTH_BASALT = get("minecraft:smooth_basalt"); + @Nullable public static final ItemType SMOOTH_QUARTZ = get("minecraft:smooth_quartz"); + @Nullable public static final ItemType SMOOTH_QUARTZ_SLAB = get("minecraft:smooth_quartz_slab"); + @Nullable public static final ItemType SMOOTH_QUARTZ_STAIRS = get("minecraft:smooth_quartz_stairs"); + @Nullable public static final ItemType SMOOTH_RED_SANDSTONE = get("minecraft:smooth_red_sandstone"); + @Nullable public static final ItemType SMOOTH_RED_SANDSTONE_SLAB = get("minecraft:smooth_red_sandstone_slab"); + @Nullable public static final ItemType SMOOTH_RED_SANDSTONE_STAIRS = get("minecraft:smooth_red_sandstone_stairs"); + @Nullable public static final ItemType SMOOTH_SANDSTONE = get("minecraft:smooth_sandstone"); + @Nullable public static final ItemType SMOOTH_SANDSTONE_SLAB = get("minecraft:smooth_sandstone_slab"); + @Nullable public static final ItemType SMOOTH_SANDSTONE_STAIRS = get("minecraft:smooth_sandstone_stairs"); + @Nullable public static final ItemType SMOOTH_STONE = get("minecraft:smooth_stone"); + @Nullable public static final ItemType SMOOTH_STONE_SLAB = get("minecraft:smooth_stone_slab"); + @Nullable public static final ItemType SNIFFER_EGG = get("minecraft:sniffer_egg"); + @Nullable public static final ItemType SNIFFER_SPAWN_EGG = get("minecraft:sniffer_spawn_egg"); + @Nullable public static final ItemType SNORT_POTTERY_SHERD = get("minecraft:snort_pottery_sherd"); + @Nullable public static final ItemType SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:snout_armor_trim_smithing_template"); + @Nullable public static final ItemType SNOW = get("minecraft:snow"); + @Nullable public static final ItemType SNOW_BLOCK = get("minecraft:snow_block"); + @Nullable public static final ItemType SNOW_GOLEM_SPAWN_EGG = get("minecraft:snow_golem_spawn_egg"); + @Nullable public static final ItemType SNOWBALL = get("minecraft:snowball"); + @Nullable public static final ItemType SOUL_CAMPFIRE = get("minecraft:soul_campfire"); + @Nullable public static final ItemType SOUL_LANTERN = get("minecraft:soul_lantern"); + @Nullable public static final ItemType SOUL_SAND = get("minecraft:soul_sand"); + @Nullable public static final ItemType SOUL_SOIL = get("minecraft:soul_soil"); + @Nullable public static final ItemType SOUL_TORCH = get("minecraft:soul_torch"); + @Nullable public static final ItemType SPAWNER = get("minecraft:spawner"); + @Nullable public static final ItemType SPECTRAL_ARROW = get("minecraft:spectral_arrow"); + @Nullable public static final ItemType SPIDER_EYE = get("minecraft:spider_eye"); + @Nullable public static final ItemType SPIDER_SPAWN_EGG = get("minecraft:spider_spawn_egg"); + @Nullable public static final ItemType SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:spire_armor_trim_smithing_template"); + @Nullable public static final ItemType SPLASH_POTION = get("minecraft:splash_potion"); + @Nullable public static final ItemType SPONGE = get("minecraft:sponge"); + @Nullable public static final ItemType SPORE_BLOSSOM = get("minecraft:spore_blossom"); + @Nullable public static final ItemType SPRUCE_BOAT = get("minecraft:spruce_boat"); + @Nullable public static final ItemType SPRUCE_BUTTON = get("minecraft:spruce_button"); + @Nullable public static final ItemType SPRUCE_CHEST_BOAT = get("minecraft:spruce_chest_boat"); + @Nullable public static final ItemType SPRUCE_DOOR = get("minecraft:spruce_door"); + @Nullable public static final ItemType SPRUCE_FENCE = get("minecraft:spruce_fence"); + @Nullable public static final ItemType SPRUCE_FENCE_GATE = get("minecraft:spruce_fence_gate"); + @Nullable public static final ItemType SPRUCE_HANGING_SIGN = get("minecraft:spruce_hanging_sign"); + @Nullable public static final ItemType SPRUCE_LEAVES = get("minecraft:spruce_leaves"); + @Nullable public static final ItemType SPRUCE_LOG = get("minecraft:spruce_log"); + @Nullable public static final ItemType SPRUCE_PLANKS = get("minecraft:spruce_planks"); + @Nullable public static final ItemType SPRUCE_PRESSURE_PLATE = get("minecraft:spruce_pressure_plate"); + @Nullable public static final ItemType SPRUCE_SAPLING = get("minecraft:spruce_sapling"); + @Nullable public static final ItemType SPRUCE_SIGN = get("minecraft:spruce_sign"); + @Nullable public static final ItemType SPRUCE_SLAB = get("minecraft:spruce_slab"); + @Nullable public static final ItemType SPRUCE_STAIRS = get("minecraft:spruce_stairs"); + @Nullable public static final ItemType SPRUCE_TRAPDOOR = get("minecraft:spruce_trapdoor"); + @Nullable public static final ItemType SPRUCE_WOOD = get("minecraft:spruce_wood"); + @Nullable public static final ItemType SPYGLASS = get("minecraft:spyglass"); + @Nullable public static final ItemType SQUID_SPAWN_EGG = get("minecraft:squid_spawn_egg"); + @Nullable public static final ItemType STICK = get("minecraft:stick"); + @Nullable public static final ItemType STICKY_PISTON = get("minecraft:sticky_piston"); + @Nullable public static final ItemType STONE = get("minecraft:stone"); + @Nullable public static final ItemType STONE_AXE = get("minecraft:stone_axe"); + @Nullable public static final ItemType STONE_BRICK_SLAB = get("minecraft:stone_brick_slab"); + @Nullable public static final ItemType STONE_BRICK_STAIRS = get("minecraft:stone_brick_stairs"); + @Nullable public static final ItemType STONE_BRICK_WALL = get("minecraft:stone_brick_wall"); + @Nullable public static final ItemType STONE_BRICKS = get("minecraft:stone_bricks"); + @Nullable public static final ItemType STONE_BUTTON = get("minecraft:stone_button"); + @Nullable public static final ItemType STONE_HOE = get("minecraft:stone_hoe"); + @Nullable public static final ItemType STONE_PICKAXE = get("minecraft:stone_pickaxe"); + @Nullable public static final ItemType STONE_PRESSURE_PLATE = get("minecraft:stone_pressure_plate"); + @Nullable public static final ItemType STONE_SHOVEL = get("minecraft:stone_shovel"); + @Nullable public static final ItemType STONE_SLAB = get("minecraft:stone_slab"); + @Nullable public static final ItemType STONE_STAIRS = get("minecraft:stone_stairs"); + @Nullable public static final ItemType STONE_SWORD = get("minecraft:stone_sword"); + @Nullable public static final ItemType STONECUTTER = get("minecraft:stonecutter"); + @Nullable public static final ItemType STRAY_SPAWN_EGG = get("minecraft:stray_spawn_egg"); + @Nullable public static final ItemType STRIDER_SPAWN_EGG = get("minecraft:strider_spawn_egg"); + @Nullable public static final ItemType STRING = get("minecraft:string"); + @Nullable public static final ItemType STRIPPED_ACACIA_LOG = get("minecraft:stripped_acacia_log"); + @Nullable public static final ItemType STRIPPED_ACACIA_WOOD = get("minecraft:stripped_acacia_wood"); + @Nullable public static final ItemType STRIPPED_BAMBOO_BLOCK = get("minecraft:stripped_bamboo_block"); + @Nullable public static final ItemType STRIPPED_BIRCH_LOG = get("minecraft:stripped_birch_log"); + @Nullable public static final ItemType STRIPPED_BIRCH_WOOD = get("minecraft:stripped_birch_wood"); + @Nullable public static final ItemType STRIPPED_CHERRY_LOG = get("minecraft:stripped_cherry_log"); + @Nullable public static final ItemType STRIPPED_CHERRY_WOOD = get("minecraft:stripped_cherry_wood"); + @Nullable public static final ItemType STRIPPED_CRIMSON_HYPHAE = get("minecraft:stripped_crimson_hyphae"); + @Nullable public static final ItemType STRIPPED_CRIMSON_STEM = get("minecraft:stripped_crimson_stem"); + @Nullable public static final ItemType STRIPPED_DARK_OAK_LOG = get("minecraft:stripped_dark_oak_log"); + @Nullable public static final ItemType STRIPPED_DARK_OAK_WOOD = get("minecraft:stripped_dark_oak_wood"); + @Nullable public static final ItemType STRIPPED_JUNGLE_LOG = get("minecraft:stripped_jungle_log"); + @Nullable public static final ItemType STRIPPED_JUNGLE_WOOD = get("minecraft:stripped_jungle_wood"); + @Nullable public static final ItemType STRIPPED_MANGROVE_LOG = get("minecraft:stripped_mangrove_log"); + @Nullable public static final ItemType STRIPPED_MANGROVE_WOOD = get("minecraft:stripped_mangrove_wood"); + @Nullable public static final ItemType STRIPPED_OAK_LOG = get("minecraft:stripped_oak_log"); + @Nullable public static final ItemType STRIPPED_OAK_WOOD = get("minecraft:stripped_oak_wood"); + @Nullable public static final ItemType STRIPPED_SPRUCE_LOG = get("minecraft:stripped_spruce_log"); + @Nullable public static final ItemType STRIPPED_SPRUCE_WOOD = get("minecraft:stripped_spruce_wood"); + @Nullable public static final ItemType STRIPPED_WARPED_HYPHAE = get("minecraft:stripped_warped_hyphae"); + @Nullable public static final ItemType STRIPPED_WARPED_STEM = get("minecraft:stripped_warped_stem"); + @Nullable public static final ItemType STRUCTURE_BLOCK = get("minecraft:structure_block"); + @Nullable public static final ItemType STRUCTURE_VOID = get("minecraft:structure_void"); + @Nullable public static final ItemType SUGAR = get("minecraft:sugar"); + @Nullable public static final ItemType SUGAR_CANE = get("minecraft:sugar_cane"); + @Nullable public static final ItemType SUNFLOWER = get("minecraft:sunflower"); + @Nullable public static final ItemType SUSPICIOUS_GRAVEL = get("minecraft:suspicious_gravel"); + @Nullable public static final ItemType SUSPICIOUS_SAND = get("minecraft:suspicious_sand"); + @Nullable public static final ItemType SUSPICIOUS_STEW = get("minecraft:suspicious_stew"); + @Nullable public static final ItemType SWEET_BERRIES = get("minecraft:sweet_berries"); + @Nullable public static final ItemType TADPOLE_BUCKET = get("minecraft:tadpole_bucket"); + @Nullable public static final ItemType TADPOLE_SPAWN_EGG = get("minecraft:tadpole_spawn_egg"); + @Nullable public static final ItemType TALL_GRASS = get("minecraft:tall_grass"); + @Nullable public static final ItemType TARGET = get("minecraft:target"); + @Nullable public static final ItemType TERRACOTTA = get("minecraft:terracotta"); + @Nullable public static final ItemType TIDE_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:tide_armor_trim_smithing_template"); + @Nullable public static final ItemType TINTED_GLASS = get("minecraft:tinted_glass"); + @Nullable public static final ItemType TIPPED_ARROW = get("minecraft:tipped_arrow"); + @Nullable public static final ItemType TNT = get("minecraft:tnt"); + @Nullable public static final ItemType TNT_MINECART = get("minecraft:tnt_minecart"); + @Nullable public static final ItemType TORCH = get("minecraft:torch"); + @Nullable public static final ItemType TORCHFLOWER = get("minecraft:torchflower"); + @Nullable public static final ItemType TORCHFLOWER_SEEDS = get("minecraft:torchflower_seeds"); + @Nullable public static final ItemType TOTEM_OF_UNDYING = get("minecraft:totem_of_undying"); + @Nullable public static final ItemType TRADER_LLAMA_SPAWN_EGG = get("minecraft:trader_llama_spawn_egg"); + @Nullable public static final ItemType TRAPPED_CHEST = get("minecraft:trapped_chest"); + @Nullable public static final ItemType TRIDENT = get("minecraft:trident"); + @Nullable public static final ItemType TRIPWIRE_HOOK = get("minecraft:tripwire_hook"); + @Nullable public static final ItemType TROPICAL_FISH = get("minecraft:tropical_fish"); + @Nullable public static final ItemType TROPICAL_FISH_BUCKET = get("minecraft:tropical_fish_bucket"); + @Nullable public static final ItemType TROPICAL_FISH_SPAWN_EGG = get("minecraft:tropical_fish_spawn_egg"); + @Nullable public static final ItemType TUBE_CORAL = get("minecraft:tube_coral"); + @Nullable public static final ItemType TUBE_CORAL_BLOCK = get("minecraft:tube_coral_block"); + @Nullable public static final ItemType TUBE_CORAL_FAN = get("minecraft:tube_coral_fan"); + @Nullable public static final ItemType TUFF = get("minecraft:tuff"); + @Nullable public static final ItemType TURTLE_EGG = get("minecraft:turtle_egg"); + @Nullable public static final ItemType TURTLE_HELMET = get("minecraft:turtle_helmet"); + @Nullable public static final ItemType TURTLE_SPAWN_EGG = get("minecraft:turtle_spawn_egg"); + @Nullable public static final ItemType TWISTING_VINES = get("minecraft:twisting_vines"); + @Nullable public static final ItemType VERDANT_FROGLIGHT = get("minecraft:verdant_froglight"); + @Nullable public static final ItemType VEX_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:vex_armor_trim_smithing_template"); + @Nullable public static final ItemType VEX_SPAWN_EGG = get("minecraft:vex_spawn_egg"); + @Nullable public static final ItemType VILLAGER_SPAWN_EGG = get("minecraft:villager_spawn_egg"); + @Nullable public static final ItemType VINDICATOR_SPAWN_EGG = get("minecraft:vindicator_spawn_egg"); + @Nullable public static final ItemType VINE = get("minecraft:vine"); + @Nullable public static final ItemType WANDERING_TRADER_SPAWN_EGG = get("minecraft:wandering_trader_spawn_egg"); + @Nullable public static final ItemType WARD_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:ward_armor_trim_smithing_template"); + @Nullable public static final ItemType WARDEN_SPAWN_EGG = get("minecraft:warden_spawn_egg"); + @Nullable public static final ItemType WARPED_BUTTON = get("minecraft:warped_button"); + @Nullable public static final ItemType WARPED_DOOR = get("minecraft:warped_door"); + @Nullable public static final ItemType WARPED_FENCE = get("minecraft:warped_fence"); + @Nullable public static final ItemType WARPED_FENCE_GATE = get("minecraft:warped_fence_gate"); + @Nullable public static final ItemType WARPED_FUNGUS = get("minecraft:warped_fungus"); + @Nullable public static final ItemType WARPED_FUNGUS_ON_A_STICK = get("minecraft:warped_fungus_on_a_stick"); + @Nullable public static final ItemType WARPED_HANGING_SIGN = get("minecraft:warped_hanging_sign"); + @Nullable public static final ItemType WARPED_HYPHAE = get("minecraft:warped_hyphae"); + @Nullable public static final ItemType WARPED_NYLIUM = get("minecraft:warped_nylium"); + @Nullable public static final ItemType WARPED_PLANKS = get("minecraft:warped_planks"); + @Nullable public static final ItemType WARPED_PRESSURE_PLATE = get("minecraft:warped_pressure_plate"); + @Nullable public static final ItemType WARPED_ROOTS = get("minecraft:warped_roots"); + @Nullable public static final ItemType WARPED_SIGN = get("minecraft:warped_sign"); + @Nullable public static final ItemType WARPED_SLAB = get("minecraft:warped_slab"); + @Nullable public static final ItemType WARPED_STAIRS = get("minecraft:warped_stairs"); + @Nullable public static final ItemType WARPED_STEM = get("minecraft:warped_stem"); + @Nullable public static final ItemType WARPED_TRAPDOOR = get("minecraft:warped_trapdoor"); + @Nullable public static final ItemType WARPED_WART_BLOCK = get("minecraft:warped_wart_block"); + @Nullable public static final ItemType WATER_BUCKET = get("minecraft:water_bucket"); + @Nullable public static final ItemType WAXED_COPPER_BLOCK = get("minecraft:waxed_copper_block"); + @Nullable public static final ItemType WAXED_CUT_COPPER = get("minecraft:waxed_cut_copper"); + @Nullable public static final ItemType WAXED_CUT_COPPER_SLAB = get("minecraft:waxed_cut_copper_slab"); + @Nullable public static final ItemType WAXED_CUT_COPPER_STAIRS = get("minecraft:waxed_cut_copper_stairs"); + @Nullable public static final ItemType WAXED_EXPOSED_COPPER = get("minecraft:waxed_exposed_copper"); + @Nullable public static final ItemType WAXED_EXPOSED_CUT_COPPER = get("minecraft:waxed_exposed_cut_copper"); + @Nullable public static final ItemType WAXED_EXPOSED_CUT_COPPER_SLAB = get("minecraft:waxed_exposed_cut_copper_slab"); + @Nullable public static final ItemType WAXED_EXPOSED_CUT_COPPER_STAIRS = get("minecraft:waxed_exposed_cut_copper_stairs"); + @Nullable public static final ItemType WAXED_OXIDIZED_COPPER = get("minecraft:waxed_oxidized_copper"); + @Nullable public static final ItemType WAXED_OXIDIZED_CUT_COPPER = get("minecraft:waxed_oxidized_cut_copper"); + @Nullable public static final ItemType WAXED_OXIDIZED_CUT_COPPER_SLAB = get("minecraft:waxed_oxidized_cut_copper_slab"); + @Nullable public static final ItemType WAXED_OXIDIZED_CUT_COPPER_STAIRS = get("minecraft:waxed_oxidized_cut_copper_stairs"); + @Nullable public static final ItemType WAXED_WEATHERED_COPPER = get("minecraft:waxed_weathered_copper"); + @Nullable public static final ItemType WAXED_WEATHERED_CUT_COPPER = get("minecraft:waxed_weathered_cut_copper"); + @Nullable public static final ItemType WAXED_WEATHERED_CUT_COPPER_SLAB = get("minecraft:waxed_weathered_cut_copper_slab"); + @Nullable public static final ItemType WAXED_WEATHERED_CUT_COPPER_STAIRS = get("minecraft:waxed_weathered_cut_copper_stairs"); + @Nullable public static final ItemType WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:wayfinder_armor_trim_smithing_template"); + @Nullable public static final ItemType WEATHERED_COPPER = get("minecraft:weathered_copper"); + @Nullable public static final ItemType WEATHERED_CUT_COPPER = get("minecraft:weathered_cut_copper"); + @Nullable public static final ItemType WEATHERED_CUT_COPPER_SLAB = get("minecraft:weathered_cut_copper_slab"); + @Nullable public static final ItemType WEATHERED_CUT_COPPER_STAIRS = get("minecraft:weathered_cut_copper_stairs"); + @Nullable public static final ItemType WEEPING_VINES = get("minecraft:weeping_vines"); + @Nullable public static final ItemType WET_SPONGE = get("minecraft:wet_sponge"); + @Nullable public static final ItemType WHEAT = get("minecraft:wheat"); + @Nullable public static final ItemType WHEAT_SEEDS = get("minecraft:wheat_seeds"); + @Nullable public static final ItemType WHITE_BANNER = get("minecraft:white_banner"); + @Nullable public static final ItemType WHITE_BED = get("minecraft:white_bed"); + @Nullable public static final ItemType WHITE_CANDLE = get("minecraft:white_candle"); + @Nullable public static final ItemType WHITE_CARPET = get("minecraft:white_carpet"); + @Nullable public static final ItemType WHITE_CONCRETE = get("minecraft:white_concrete"); + @Nullable public static final ItemType WHITE_CONCRETE_POWDER = get("minecraft:white_concrete_powder"); + @Nullable public static final ItemType WHITE_DYE = get("minecraft:white_dye"); + @Nullable public static final ItemType WHITE_GLAZED_TERRACOTTA = get("minecraft:white_glazed_terracotta"); + @Nullable public static final ItemType WHITE_SHULKER_BOX = get("minecraft:white_shulker_box"); + @Nullable public static final ItemType WHITE_STAINED_GLASS = get("minecraft:white_stained_glass"); + @Nullable public static final ItemType WHITE_STAINED_GLASS_PANE = get("minecraft:white_stained_glass_pane"); + @Nullable public static final ItemType WHITE_TERRACOTTA = get("minecraft:white_terracotta"); + @Nullable public static final ItemType WHITE_TULIP = get("minecraft:white_tulip"); + @Nullable public static final ItemType WHITE_WOOL = get("minecraft:white_wool"); + @Nullable public static final ItemType WILD_ARMOR_TRIM_SMITHING_TEMPLATE = get("minecraft:wild_armor_trim_smithing_template"); + @Nullable public static final ItemType WITCH_SPAWN_EGG = get("minecraft:witch_spawn_egg"); + @Nullable public static final ItemType WITHER_ROSE = get("minecraft:wither_rose"); + @Nullable public static final ItemType WITHER_SKELETON_SKULL = get("minecraft:wither_skeleton_skull"); + @Nullable public static final ItemType WITHER_SKELETON_SPAWN_EGG = get("minecraft:wither_skeleton_spawn_egg"); + @Nullable public static final ItemType WITHER_SPAWN_EGG = get("minecraft:wither_spawn_egg"); + @Nullable public static final ItemType WOLF_SPAWN_EGG = get("minecraft:wolf_spawn_egg"); + @Nullable public static final ItemType WOODEN_AXE = get("minecraft:wooden_axe"); + @Nullable public static final ItemType WOODEN_HOE = get("minecraft:wooden_hoe"); + @Nullable public static final ItemType WOODEN_PICKAXE = get("minecraft:wooden_pickaxe"); + @Nullable public static final ItemType WOODEN_SHOVEL = get("minecraft:wooden_shovel"); + @Nullable public static final ItemType WOODEN_SWORD = get("minecraft:wooden_sword"); + @Nullable public static final ItemType WRITABLE_BOOK = get("minecraft:writable_book"); + @Nullable public static final ItemType WRITTEN_BOOK = get("minecraft:written_book"); + @Nullable public static final ItemType YELLOW_BANNER = get("minecraft:yellow_banner"); + @Nullable public static final ItemType YELLOW_BED = get("minecraft:yellow_bed"); + @Nullable public static final ItemType YELLOW_CANDLE = get("minecraft:yellow_candle"); + @Nullable public static final ItemType YELLOW_CARPET = get("minecraft:yellow_carpet"); + @Nullable public static final ItemType YELLOW_CONCRETE = get("minecraft:yellow_concrete"); + @Nullable public static final ItemType YELLOW_CONCRETE_POWDER = get("minecraft:yellow_concrete_powder"); + @Nullable public static final ItemType YELLOW_DYE = get("minecraft:yellow_dye"); + @Nullable public static final ItemType YELLOW_GLAZED_TERRACOTTA = get("minecraft:yellow_glazed_terracotta"); + @Nullable public static final ItemType YELLOW_SHULKER_BOX = get("minecraft:yellow_shulker_box"); + @Nullable public static final ItemType YELLOW_STAINED_GLASS = get("minecraft:yellow_stained_glass"); + @Nullable public static final ItemType YELLOW_STAINED_GLASS_PANE = get("minecraft:yellow_stained_glass_pane"); + @Nullable public static final ItemType YELLOW_TERRACOTTA = get("minecraft:yellow_terracotta"); + @Nullable public static final ItemType YELLOW_WOOL = get("minecraft:yellow_wool"); + @Nullable public static final ItemType ZOGLIN_SPAWN_EGG = get("minecraft:zoglin_spawn_egg"); + @Nullable public static final ItemType ZOMBIE_HEAD = get("minecraft:zombie_head"); + @Nullable public static final ItemType ZOMBIE_HORSE_SPAWN_EGG = get("minecraft:zombie_horse_spawn_egg"); + @Deprecated @Nullable public static final ItemType ZOMBIE_PIGMAN_SPAWN_EGG = get("minecraft:zombie_pigman_spawn_egg"); + @Nullable public static final ItemType ZOMBIE_SPAWN_EGG = get("minecraft:zombie_spawn_egg"); + @Nullable public static final ItemType ZOMBIE_VILLAGER_SPAWN_EGG = get("minecraft:zombie_villager_spawn_egg"); + @Nullable public static final ItemType ZOMBIFIED_PIGLIN_SPAWN_EGG = get("minecraft:zombified_piglin_spawn_egg"); + + private ItemTypes() { + } + + /** + * Gets the {@link ItemType} associated with the given id. + */ + public static @Nullable ItemType get(String id) { + return ItemType.REGISTRY.get(id); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BiomeRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/BiomeRegistry.java new file mode 100644 index 0000000..6bbad6b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BiomeRegistry.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import net.kyori.text.Component; +import com.sk89q.worldedit.world.biome.BiomeData; +import com.sk89q.worldedit.world.biome.BiomeType; + +import javax.annotation.Nullable; + +/** + * Provides information on biomes. + */ +public interface BiomeRegistry { + + /** + * Get the name of the biome, usually as a translatable component. + * + * @param biomeType the biome type + * @return the name of the biome + */ + Component getRichName(BiomeType biomeType); + + /** + * Get data about a biome. + * + * @param biome the biome + * @return a data object or null if information is not known + * @deprecated This method no longer returns any useful information. + * Use {@link #getRichName(BiomeType)} for the name of the biome. + */ + @Deprecated + @Nullable + BiomeData getData(BiomeType biome); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BlockCategoryRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/BlockCategoryRegistry.java new file mode 100644 index 0000000..f55d1a2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BlockCategoryRegistry.java @@ -0,0 +1,29 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.world.block.BlockType; + +/** + * A registry for BlockType categories. + */ +public interface BlockCategoryRegistry extends CategoryRegistry { + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java b/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java new file mode 100644 index 0000000..d280f2c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java @@ -0,0 +1,161 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +/** + * Describes the material for a block. + */ +public interface BlockMaterial { + + /** + * Gets if this block is a type of air. + * + * @return If it's air + */ + boolean isAir(); + + /** + * Get whether this block is a full sized cube. + * + * @return the value of the test + */ + boolean isFullCube(); + + /** + * Get whether this block is opaque. + * + * @return the value of the test + */ + boolean isOpaque(); + + /** + * Get whether this block emits a Redstone signal. + * + * @return the value of the test + */ + boolean isPowerSource(); + + /** + * Get whether this block is a liquid. + * + * @return the value of the test + */ + boolean isLiquid(); + + /** + * Get whether this block is a solid. + * + * @return the value of the test + */ + boolean isSolid(); + + /** + * Get the hardness factor for this block. + * + * @return the hardness factor + */ + float getHardness(); + + /** + * Get the resistance factor for this block. + * + * @return the resistance factor + */ + float getResistance(); + + /** + * Get the slipperiness factor for this block. + * + * @return the slipperiness factor + */ + float getSlipperiness(); + + /** + * Get the light value for this block. + * + * @return the light value + */ + int getLightValue(); + + /** + * Get whether this block breaks when it is pushed by a piston. + * + * @return true if the block breaks + */ + boolean isFragileWhenPushed(); + + /** + * Get whether this block can be pushed by a piston. + * + * @return true if the block cannot be pushed + */ + boolean isUnpushable(); + + /** + * Get whether this block is ticked randomly. + * + * @return true if this block is ticked randomly + */ + boolean isTicksRandomly(); + + /** + * Get whether this block prevents movement. + * + * @return true if this block blocks movement + */ + boolean isMovementBlocker(); + + /** + * Get whether this block will burn. + * + * @return true if this block will burn + */ + boolean isBurnable(); + + /** + * Get whether this block needs to be broken by a tool for maximum + * speed. + * + * @return true if a tool is required + */ + boolean isToolRequired(); + + /** + * Get whether this block is replaced when a block is placed over it + * (for example, tall grass). + * + * @return true if the block is replaced + */ + boolean isReplacedDuringPlacement(); + + /** + * Get whether this block is translucent. + * + * @return true if the block is translucent + */ + boolean isTranslucent(); + + /** + * Gets whether the block has a container (Item container). + * + * @return If it has a container + */ + boolean hasContainer(); +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java new file mode 100644 index 0000000..c7229d5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java @@ -0,0 +1,82 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.registry.state.Property; +import net.kyori.text.Component; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.OptionalInt; + +/** + * Provides information on blocks and provides methods to create them. + */ +public interface BlockRegistry { + + /** + * Gets the name for the given block. + * + * @param blockType the block + * @return The name + */ + Component getRichName(BlockType blockType); + + /** + * Gets the name for the given block. + * + * @param blockType the block + * @return The name, or null if it's unknown + * @deprecated Names are now translatable, use {@link #getRichName(BlockType)}. + */ + @Deprecated + @Nullable + default String getName(BlockType blockType) { + return getRichName(blockType).toString(); + } + + /** + * Get the material for the given block. + * + * @param blockType the block + * @return the material, or null if the material information is not known + */ + @Nullable + BlockMaterial getMaterial(BlockType blockType); + + /** + * Get an unmodifiable map of states for this block. + * + * @param blockType the block + * @return a map of states where the key is the state's ID + */ + Map> getProperties(BlockType blockType); + + /** + * Retrieve the internal ID for a given state, if possible. + * + * @param state The block state + * @return the internal ID of the state + */ + OptionalInt getInternalBlockStateId(BlockState state); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java b/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java new file mode 100644 index 0000000..807ee83 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java @@ -0,0 +1,136 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.google.common.io.Resources; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.gson.VectorAdapter; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * Provides block data based on the built-in block database that is bundled + * with WorldEdit. + * + *

A new instance cannot be created. Use {@link #getInstance()} to get + * an instance.

+ * + *

The data is read from a JSON file that is bundled with WorldEdit. If + * reading fails (which occurs when this class is first instantiated), then + * the methods will return {@code null}s for all blocks.

+ */ +public final class BundledBlockData { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static BundledBlockData INSTANCE; + + private final Map idMap = new HashMap<>(); + + /** + * Create a new instance. + */ + private BundledBlockData() { + try { + loadFromResource(); + } catch (Throwable e) { + LOGGER.warn("Failed to load the built-in block registry", e); + } + } + + /** + * Attempt to load the data from file. + * + * @throws IOException thrown on I/O error + */ + private void loadFromResource() throws IOException { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); + Gson gson = gsonBuilder.create(); + URL url = BundledRegistries.loadRegistry("blocks"); + LOGGER.debug("Using {} for bundled block data.", url); + String data = Resources.toString(url, Charset.defaultCharset()); + List entries = gson.fromJson(data, new TypeToken>() {}.getType()); + + for (BlockEntry entry : entries) { + idMap.put(entry.id, entry); + } + } + + /** + * Return the entry for the given block ID. + * + * @param id the ID + * @return the entry, or null + */ + @Nullable + public BlockEntry findById(String id) { + // If it has no namespace, assume minecraft. + if (!id.contains(":")) { + id = "minecraft:" + id; + } + return idMap.get(id); + } + + /** + * Get the material properties for the given block. + * + * @param id the string ID + * @return the material's properties, or null + */ + @Nullable + public BlockMaterial getMaterialById(String id) { + BlockEntry entry = findById(id); + if (entry != null) { + return entry.material; + } else { + return null; + } + } + + /** + * Get a singleton instance of this object. + * + * @return the instance + */ + public static BundledBlockData getInstance() { + if (INSTANCE == null) { + INSTANCE = new BundledBlockData(); + } + return INSTANCE; + } + + public static class BlockEntry { + private String id; + public String localizedName; + private final SimpleBlockMaterial material = new SimpleBlockMaterial(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java new file mode 100644 index 0000000..0ffb377 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java @@ -0,0 +1,83 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.registry.state.Property; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.util.translation.TranslationManager; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.Collections; +import java.util.Map; +import java.util.OptionalInt; +import javax.annotation.Nullable; + +/** + * A block registry that uses {@link BundledBlockData} to serve information + * about blocks. + */ +public class BundledBlockRegistry implements BlockRegistry { + + @Override + public Component getRichName(BlockType blockType) { + BundledBlockData.BlockEntry blockEntry = BundledBlockData.getInstance().findById(blockType.getId()); + if (blockEntry != null) { + // This is more likely to be "right", but not translated + // Some vanilla MC blocks have overrides so we need this name here + // Most platforms should be overriding this anyways, so it likely doesn't matter + // too much! + return TextComponent.of(blockEntry.localizedName); + } + return TranslatableComponent.of( + TranslationManager.makeTranslationKey("block", blockType.getId()) + ); + } + + @Nullable + @Override + @Deprecated + // dumb_intellij.jpg + @SuppressWarnings("deprecation") + public String getName(BlockType blockType) { + BundledBlockData.BlockEntry blockEntry = BundledBlockData.getInstance().findById(blockType.getId()); + return blockEntry != null ? blockEntry.localizedName : null; + } + + @Nullable + @Override + public BlockMaterial getMaterial(BlockType blockType) { + return new PassthroughBlockMaterial(BundledBlockData.getInstance().getMaterialById(blockType.getId())); + } + + @Nullable + @Override + public Map> getProperties(BlockType blockType) { + return Collections.emptyMap(); // Oof + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + return OptionalInt.empty(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java b/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java new file mode 100644 index 0000000..53f362a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java @@ -0,0 +1,139 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.google.common.io.Resources; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.gson.VectorAdapter; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Provides item data based on the built-in item database that is bundled + * with WorldEdit. + * + *

A new instance cannot be created. Use {@link #getInstance()} to get + * an instance.

+ * + *

The data is read from a JSON file that is bundled with WorldEdit. If + * reading fails (which occurs when this class is first instantiated), then + * the methods will return {@code null}s for all items.

+ */ +public final class BundledItemData { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static BundledItemData INSTANCE; + + private final Map idMap = new HashMap<>(); + + /** + * Create a new instance. + */ + private BundledItemData() { + try { + loadFromResource(); + } catch (Throwable e) { + LOGGER.warn("Failed to load the built-in item registry", e); + } + } + + /** + * Attempt to load the data from file. + * + * @throws IOException thrown on I/O error + */ + private void loadFromResource() throws IOException { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); + Gson gson = gsonBuilder.create(); + URL url = BundledRegistries.loadRegistry("items"); + LOGGER.debug("Using {} for bundled item data.", url); + String data = Resources.toString(url, Charset.defaultCharset()); + List entries = gson.fromJson(data, new TypeToken>() {}.getType()); + + for (ItemEntry entry : entries) { + idMap.put(entry.id, entry); + } + } + + /** + * Return the entry for the given item ID. + * + * @param id the ID + * @return the entry, or null + */ + @Nullable + public ItemEntry findById(String id) { + // If it has no namespace, assume minecraft. + if (!id.contains(":")) { + id = "minecraft:" + id; + } + return idMap.get(id); + } + + /** + * Get the material properties for the given item. + * + * @param id the string ID + * @return the material's properties, or null + */ + @Nullable + public ItemMaterial getMaterialById(String id) { + ItemEntry entry = findById(id); + if (entry != null) { + // FIXME: This should probably just be part of the JSON itself + return new SimpleItemMaterial(entry.maxStackSize, entry.maxDamage); + } else { + return null; + } + } + + /** + * Get a singleton instance of this object. + * + * @return the instance + */ + public static BundledItemData getInstance() { + if (INSTANCE == null) { + INSTANCE = new BundledItemData(); + } + return INSTANCE; + } + + public static class ItemEntry { + private String id; + private String unlocalizedName; + public String localizedName; + private int maxDamage; + private int maxStackSize; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java new file mode 100644 index 0000000..9a81d1a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java @@ -0,0 +1,79 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.util.translation.TranslationManager; +import com.sk89q.worldedit.world.item.ItemType; + +import javax.annotation.Nullable; + +/** + * A item registry that uses {@link BundledItemRegistry} to serve information + * about items. + */ +public class BundledItemRegistry implements ItemRegistry { + + private BundledItemData.ItemEntry getEntryById(ItemType itemType) { + return BundledItemData.getInstance().findById(itemType.getId()); + } + + @Override + public Component getRichName(ItemType itemType) { + BundledItemData.ItemEntry itemEntry = getEntryById(itemType); + if (itemEntry != null && !itemEntry.localizedName.equals("Air")) { + // This is more likely to be "right", but not translated + // Some vanilla MC items have overrides so we need this name here + // Most platforms should be overriding this anyways, so it likely doesn't matter + // too much! + return TextComponent.of(itemEntry.localizedName); + } + return TranslatableComponent.of( + TranslationManager.makeTranslationKey("item", itemType.getId()) + ); + } + + @Nullable + @Override + @Deprecated + // dumb_intellij.jpg + @SuppressWarnings("deprecation") + public String getName(ItemType itemType) { + BundledItemData.ItemEntry itemEntry = getEntryById(itemType); + if (itemEntry != null) { + String localized = itemEntry.localizedName; + if (localized.equals("Air")) { + String id = itemType.getId(); + int c = id.indexOf(':'); + return c < 0 ? id : id.substring(c + 1); + } + return localized; + } + return null; + } + + @Nullable + @Override + public ItemMaterial getMaterial(ItemType itemType) { + return new PassthroughItemMaterial(BundledItemData.getInstance().getMaterialById(itemType.getId())); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/BundledRegistries.java b/src/main/java/com/sk89q/worldedit/world/registry/BundledRegistries.java new file mode 100644 index 0000000..c37f3d3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/BundledRegistries.java @@ -0,0 +1,124 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.google.common.collect.ImmutableRangeMap; +import com.google.common.collect.Range; +import com.google.common.collect.RangeMap; +import com.google.common.collect.TreeRangeMap; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.util.io.ResourceLoader; + +import java.io.IOException; +import java.net.URL; + +/** + * An implementation of {@link Registries} that converts legacy numeric IDs and + * a contains a built-in block and item database. + */ +public class BundledRegistries implements Registries { + + private static final BundledRegistries INSTANCE = new BundledRegistries(); + + private static final RangeMap VERSION_MAP; + + static { + TreeRangeMap versionMap = TreeRangeMap.create(); + versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_14), "114"); + versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_15), "115"); + versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_16), "116"); + versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_17), "117"); + // 1.18 did have one item change, but we didn't get it. It's fine. + versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_19), "119"); + versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_20), "120"); + VERSION_MAP = ImmutableRangeMap.copyOf(versionMap); + } + + static URL loadRegistry(String name) throws IOException { + ResourceLoader resourceLoader = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.CONFIGURATION) + .getResourceLoader(); + int dataVersion = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING) + .getDataVersion(); + String version = VERSION_MAP.get(dataVersion); + URL url = resourceLoader.getResource(BundledRegistries.class, name + "." + version + ".json"); + if (url == null) { + url = resourceLoader.getResource(BundledRegistries.class, name + ".json"); + } + if (url == null) { + throw new IOException("Could not find " + name + ".json"); + } + return url; + } + + private final BundledBlockRegistry blockRegistry = new BundledBlockRegistry(); + private final BundledItemRegistry itemRegistry = new BundledItemRegistry(); + private final NullEntityRegistry entityRegistry = new NullEntityRegistry(); + private final NullBiomeRegistry biomeRegistry = new NullBiomeRegistry(); + private final NullBlockCategoryRegistry blockCategoryRegistry = new NullBlockCategoryRegistry(); + private final NullItemCategoryRegistry itemCategoryRegistry = new NullItemCategoryRegistry(); + + /** + * Create a new instance. + */ + protected BundledRegistries() { + } + + @Override + public BlockRegistry getBlockRegistry() { + return blockRegistry; + } + + @Override + public ItemRegistry getItemRegistry() { + return itemRegistry; + } + + @Override + public EntityRegistry getEntityRegistry() { + return entityRegistry; + } + + @Override + public BiomeRegistry getBiomeRegistry() { + return biomeRegistry; + } + + @Override + public BlockCategoryRegistry getBlockCategoryRegistry() { + return blockCategoryRegistry; + } + + @Override + public ItemCategoryRegistry getItemCategoryRegistry() { + return itemCategoryRegistry; + } + + /** + * Get a singleton instance. + * + * @return an instance + */ + public static BundledRegistries getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java new file mode 100644 index 0000000..99ddb10 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.registry.Keyed; + +import java.util.Set; + +/** + * A registry of categories. Minecraft internally calls these 'Tags'. + */ +public interface CategoryRegistry { + + /** + * Gets a set of values with a given category. + * + * @param category The category + * @return A set of values + */ + Set getCategorisedByName(String category); + + default Set getAll(final Category category) { + return getCategorisedByName(category.getId()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/EntityRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/EntityRegistry.java new file mode 100644 index 0000000..51e40f9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/EntityRegistry.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.entity.BaseEntity; + +import javax.annotation.Nullable; + +/** + * Provides information on entities. + */ +public interface EntityRegistry { + + /** + * Create a new entity using its ID. + * + * @param id the id + * @return the entity, which may be null if the entity does not exist + */ + @Nullable + BaseEntity createFromId(String id); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/ItemCategoryRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/ItemCategoryRegistry.java new file mode 100644 index 0000000..6eed49e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/ItemCategoryRegistry.java @@ -0,0 +1,29 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.world.item.ItemType; + +/** + * A registry for ItemType categories. + */ +public interface ItemCategoryRegistry extends CategoryRegistry { + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java b/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java new file mode 100644 index 0000000..f806c91 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java @@ -0,0 +1,36 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +public interface ItemMaterial { + /** + * Gets the the maximum quantity of this item that can be in a single stack. + * + * @return the maximum quantity + */ + int getMaxStackSize(); + + /** + * Gets the the maximum damage this item can take before being broken. + * + * @return the maximum damage, or 0 if not applicable + */ + int getMaxDamage(); +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/ItemRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/ItemRegistry.java new file mode 100644 index 0000000..c31e491 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/ItemRegistry.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.blocks.BaseItemStack; +import net.kyori.text.Component; +import com.sk89q.worldedit.world.item.ItemType; + +import javax.annotation.Nullable; + +public interface ItemRegistry { + + /** + * Gets the name for the given item. + * + * @param itemType the item + * @return The name + */ + Component getRichName(ItemType itemType); + + /** + * Gets the name for the given item stack. + * + * @param itemStack the item stack + * @return The name + */ + default Component getRichName(BaseItemStack itemStack) { + return getRichName(itemStack.getType()); + } + + /** + * Gets the name for the given item. + * + * @param itemType the item + * @return The name, or null if it's unknown + * @deprecated Names are now translatable, use {@link #getRichName(ItemType)}. + */ + @Deprecated + @Nullable + default String getName(ItemType itemType) { + return getRichName(itemType).toString(); + } + + /** + * Get the material for the given item. + * + * @param itemType the item + * @return the material, or null if the material information is not known + */ + @Nullable + ItemMaterial getMaterial(ItemType itemType); +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java b/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java new file mode 100644 index 0000000..e6e20f1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java @@ -0,0 +1,201 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.io.Resources; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.factory.BlockFactory; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.gson.VectorAdapter; +import com.sk89q.worldedit.util.io.ResourceLoader; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nullable; + +public final class LegacyMapper { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static LegacyMapper INSTANCE; + private final ResourceLoader resourceLoader; + + private final Map stringToBlockMap = new HashMap<>(); + private final Multimap blockToStringMap = HashMultimap.create(); + private final Map stringToItemMap = new HashMap<>(); + private final Multimap itemToStringMap = HashMultimap.create(); + + /** + * Create a new instance. + */ + private LegacyMapper() { + this.resourceLoader = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.CONFIGURATION).getResourceLoader(); + + try { + loadFromResource(); + } catch (Throwable e) { + LOGGER.warn("Failed to load the built-in legacy id registry", e); + } + } + + /** + * Attempt to load the data from file. + * + * @throws IOException thrown on I/O error + */ + private void loadFromResource() throws IOException { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); + Gson gson = gsonBuilder.disableHtmlEscaping().create(); + URL url = resourceLoader.getResource(LegacyMapper.class, "legacy.json"); + if (url == null) { + throw new IOException("Could not find legacy.json"); + } + String data = Resources.toString(url, Charset.defaultCharset()); + LegacyDataFile dataFile = gson.fromJson(data, new TypeToken() {}.getType()); + + DataFixer fixer = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataFixer(); + ParserContext parserContext = new ParserContext(); + parserContext.setPreferringWildcard(false); + parserContext.setRestricted(false); + parserContext.setTryLegacy(false); // This is legacy. Don't match itself. + + for (Map.Entry blockEntry : dataFile.blocks.entrySet()) { + String id = blockEntry.getKey(); + final String value = blockEntry.getValue(); + + BlockState state = null; + BlockFactory blockFactory = WorldEdit.getInstance().getBlockFactory(); + + // if fixer is available, try using that first, as some old blocks that were renamed share names with new blocks + if (fixer != null) { + try { + String newEntry = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, value, Constants.DATA_VERSION_MC_1_13_2); + state = blockFactory.parseFromInput(newEntry, parserContext).toImmutableState(); + } catch (InputParseException ignored) { + } + } + + // if it's still null, the fixer was unavailable or failed + if (state == null) { + try { + state = blockFactory.parseFromInput(value, parserContext).toImmutableState(); + } catch (InputParseException ignored) { + } + } + + // if it's still null, both fixer and default failed + if (state == null) { + LOGGER.debug("Unknown block: " + value); + } else { + // it's not null so one of them succeeded, now use it + blockToStringMap.put(state, id); + stringToBlockMap.put(id, state); + } + } + + for (Map.Entry itemEntry : dataFile.items.entrySet()) { + String id = itemEntry.getKey(); + String value = itemEntry.getValue(); + ItemType type = ItemTypes.get(value); + if (type == null && fixer != null) { + value = fixer.fixUp(DataFixer.FixTypes.ITEM_TYPE, value, Constants.DATA_VERSION_MC_1_13_2); + type = ItemTypes.get(value); + } + if (type == null) { + LOGGER.debug("Unknown item: " + value); + } else { + itemToStringMap.put(type, id); + stringToItemMap.put(id, type); + } + } + } + + @Nullable + public ItemType getItemFromLegacy(int legacyId) { + return getItemFromLegacy(legacyId, 0); + } + + @Nullable + public ItemType getItemFromLegacy(int legacyId, int data) { + return stringToItemMap.get(legacyId + ":" + data); + } + + @Nullable + public int[] getLegacyFromItem(ItemType itemType) { + if (itemToStringMap.containsKey(itemType)) { + String value = itemToStringMap.get(itemType).stream().findFirst().get(); + return Arrays.stream(value.split(":")).mapToInt(Integer::parseInt).toArray(); + } else { + return null; + } + } + + @Nullable + public BlockState getBlockFromLegacy(int legacyId) { + return getBlockFromLegacy(legacyId, 0); + } + + @Nullable + public BlockState getBlockFromLegacy(int legacyId, int data) { + return stringToBlockMap.get(legacyId + ":" + data); + } + + @Nullable + public int[] getLegacyFromBlock(BlockState blockState) { + if (blockToStringMap.containsKey(blockState)) { + String value = blockToStringMap.get(blockState).stream().findFirst().get(); + return Arrays.stream(value.split(":")).mapToInt(Integer::parseInt).toArray(); + } else { + return null; + } + } + + public static LegacyMapper getInstance() { + if (INSTANCE == null) { + INSTANCE = new LegacyMapper(); + } + return INSTANCE; + } + + @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"}) + private static class LegacyDataFile { + private Map blocks; + private Map items; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java new file mode 100644 index 0000000..681146b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java @@ -0,0 +1,55 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import net.kyori.text.Component; +import net.kyori.text.TranslatableComponent; +import com.sk89q.worldedit.util.translation.TranslationManager; +import com.sk89q.worldedit.world.biome.BiomeData; +import com.sk89q.worldedit.world.biome.BiomeType; + +import javax.annotation.Nullable; + +/** + * A biome registry that knows nothing. + */ +public class NullBiomeRegistry implements BiomeRegistry { + + /** + * Create a new instance. + */ + public NullBiomeRegistry() { + } + + @Override + public Component getRichName(BiomeType biomeType) { + return TranslatableComponent.of( + TranslationManager.makeTranslationKey("biome", biomeType.getId()) + ); + } + + @Deprecated + @Nullable + @Override + public BiomeData getData(BiomeType biome) { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/NullBlockCategoryRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/NullBlockCategoryRegistry.java new file mode 100644 index 0000000..578bef7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/NullBlockCategoryRegistry.java @@ -0,0 +1,33 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.Collections; +import java.util.Set; + +public class NullBlockCategoryRegistry implements BlockCategoryRegistry { + + @Override + public Set getCategorisedByName(String category) { + return Collections.emptySet(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/NullEntityRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/NullEntityRegistry.java new file mode 100644 index 0000000..1ed1f82 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/NullEntityRegistry.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.entity.BaseEntity; + +import javax.annotation.Nullable; + +/** + * An implementation of an entity registry that knows nothing. + */ +public class NullEntityRegistry implements EntityRegistry { + + @Nullable + @Override + public BaseEntity createFromId(String id) { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/NullItemCategoryRegistry.java b/src/main/java/com/sk89q/worldedit/world/registry/NullItemCategoryRegistry.java new file mode 100644 index 0000000..b226b3d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/NullItemCategoryRegistry.java @@ -0,0 +1,33 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.world.item.ItemType; + +import java.util.Collections; +import java.util.Set; + +public class NullItemCategoryRegistry implements ItemCategoryRegistry { + + @Override + public Set getCategorisedByName(String category) { + return Collections.emptySet(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java b/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java new file mode 100644 index 0000000..e868276 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java @@ -0,0 +1,140 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import javax.annotation.Nullable; + +import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; + +public class PassthroughBlockMaterial implements BlockMaterial { + + private static final SimpleBlockMaterial DEFAULT_MATERIAL = new SimpleBlockMaterial(); + + static { + DEFAULT_MATERIAL.setFullCube(true); + DEFAULT_MATERIAL.setOpaque(true); + DEFAULT_MATERIAL.setSolid(true); + DEFAULT_MATERIAL.setTicksRandomly(true); + DEFAULT_MATERIAL.setMovementBlocker(true); + DEFAULT_MATERIAL.setBurnable(true); + DEFAULT_MATERIAL.setToolRequired(true); + } + + private final BlockMaterial blockMaterial; + + public PassthroughBlockMaterial(@Nullable BlockMaterial material) { + this.blockMaterial = firstNonNull(material, DEFAULT_MATERIAL); + } + + @Override + public boolean isAir() { + return blockMaterial.isAir(); + } + + @Override + public boolean isFullCube() { + return blockMaterial.isFullCube(); + } + + @Override + public boolean isOpaque() { + return blockMaterial.isOpaque(); + } + + @Override + public boolean isPowerSource() { + return blockMaterial.isPowerSource(); + } + + @Override + public boolean isLiquid() { + return blockMaterial.isLiquid(); + } + + @Override + public boolean isSolid() { + return blockMaterial.isSolid(); + } + + @Override + public float getHardness() { + return blockMaterial.getHardness(); + } + + @Override + public float getResistance() { + return blockMaterial.getResistance(); + } + + @Override + public float getSlipperiness() { + return blockMaterial.getSlipperiness(); + } + + @Override + public int getLightValue() { + return blockMaterial.getLightValue(); + } + + @Override + public boolean isFragileWhenPushed() { + return blockMaterial.isFragileWhenPushed(); + } + + @Override + public boolean isUnpushable() { + return blockMaterial.isUnpushable(); + } + + @Override + public boolean isTicksRandomly() { + return blockMaterial.isTicksRandomly(); + } + + @Override + public boolean isMovementBlocker() { + return blockMaterial.isMovementBlocker(); + } + + @Override + public boolean isBurnable() { + return blockMaterial.isBurnable(); + } + + @Override + public boolean isToolRequired() { + return blockMaterial.isToolRequired(); + } + + @Override + public boolean isReplacedDuringPlacement() { + return blockMaterial.isReplacedDuringPlacement(); + } + + @Override + public boolean isTranslucent() { + return blockMaterial.isTranslucent(); + } + + @Override + public boolean hasContainer() { + return blockMaterial.hasContainer(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java b/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java new file mode 100644 index 0000000..3d220aa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +import javax.annotation.Nullable; + +import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; + +public class PassthroughItemMaterial implements ItemMaterial { + + private static final ItemMaterial DEFAULT_MATERIAL = new SimpleItemMaterial(0, 0); + + private final ItemMaterial itemMaterial; + + public PassthroughItemMaterial(@Nullable ItemMaterial material) { + this.itemMaterial = firstNonNull(material, DEFAULT_MATERIAL); + } + + @Override + public int getMaxStackSize() { + return itemMaterial.getMaxStackSize(); + } + + @Override + public int getMaxDamage() { + return itemMaterial.getMaxDamage(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/Registries.java b/src/main/java/com/sk89q/worldedit/world/registry/Registries.java new file mode 100644 index 0000000..94cdb12 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/Registries.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +/** + * Contains getters for the various registries. + */ +public interface Registries { + + /** + * Get the block registry. + * + * @return the block registry + */ + BlockRegistry getBlockRegistry(); + + /** + * Get the item registry. + * + * @return the item registry + */ + ItemRegistry getItemRegistry(); + + /** + * Get the entity registry. + * + * @return the entity registry + */ + EntityRegistry getEntityRegistry(); + + /** + * Get the biome registry. + * + * @return the biome registry + */ + BiomeRegistry getBiomeRegistry(); + + /** + * Get the block category registry. + * + * @return the block category registry + */ + BlockCategoryRegistry getBlockCategoryRegistry(); + + /** + * Get the item category registry. + * + * @return the item category registry + */ + ItemCategoryRegistry getItemCategoryRegistry(); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java b/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java new file mode 100644 index 0000000..de70a38 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java @@ -0,0 +1,214 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +class SimpleBlockMaterial implements BlockMaterial { + + private boolean isAir; + private boolean fullCube; + private boolean opaque; + private boolean powerSource; + private boolean liquid; + private boolean solid; + private float hardness; + private float resistance; + private float slipperiness; + private int lightValue; + private boolean fragileWhenPushed; + private boolean unpushable; + private boolean ticksRandomly; + private boolean movementBlocker; + private boolean burnable; + private boolean toolRequired; + private boolean replacedDuringPlacement; + private boolean isTranslucent; + private boolean hasContainer; + + @Override + public boolean isAir() { + return this.isAir; + } + + public void setIsAir(boolean isAir) { + this.isAir = isAir; + } + + @Override + public boolean isFullCube() { + return fullCube; + } + + public void setFullCube(boolean fullCube) { + this.fullCube = fullCube; + } + + @Override + public boolean isOpaque() { + return opaque; + } + + public void setOpaque(boolean opaque) { + this.opaque = opaque; + } + + @Override + public boolean isPowerSource() { + return powerSource; + } + + public void setPowerSource(boolean powerSource) { + this.powerSource = powerSource; + } + + @Override + public boolean isLiquid() { + return liquid; + } + + public void setLiquid(boolean liquid) { + this.liquid = liquid; + } + + @Override + public boolean isSolid() { + return solid; + } + + public void setSolid(boolean solid) { + this.solid = solid; + } + + @Override + public float getHardness() { + return hardness; + } + + public void setHardness(float hardness) { + this.hardness = hardness; + } + + @Override + public float getResistance() { + return resistance; + } + + public void setResistance(float resistance) { + this.resistance = resistance; + } + + @Override + public float getSlipperiness() { + return slipperiness; + } + + public void setSlipperiness(float slipperiness) { + this.slipperiness = slipperiness; + } + + @Override + public int getLightValue() { + return lightValue; + } + + public void setLightValue(int lightValue) { + this.lightValue = lightValue; + } + + @Override + public boolean isFragileWhenPushed() { + return fragileWhenPushed; + } + + public void setFragileWhenPushed(boolean fragileWhenPushed) { + this.fragileWhenPushed = fragileWhenPushed; + } + + @Override + public boolean isUnpushable() { + return unpushable; + } + + public void setUnpushable(boolean unpushable) { + this.unpushable = unpushable; + } + + @Override + public boolean isTicksRandomly() { + return ticksRandomly; + } + + public void setTicksRandomly(boolean ticksRandomly) { + this.ticksRandomly = ticksRandomly; + } + + @Override + public boolean isMovementBlocker() { + return movementBlocker; + } + + public void setMovementBlocker(boolean movementBlocker) { + this.movementBlocker = movementBlocker; + } + + @Override + public boolean isBurnable() { + return burnable; + } + + public void setBurnable(boolean burnable) { + this.burnable = burnable; + } + + @Override + public boolean isToolRequired() { + return toolRequired; + } + + public void setToolRequired(boolean toolRequired) { + this.toolRequired = toolRequired; + } + + @Override + public boolean isReplacedDuringPlacement() { + return replacedDuringPlacement; + } + + public void setTranslucent(boolean isTranslucent) { + this.isTranslucent = isTranslucent; + } + + @Override + public boolean isTranslucent() { + return this.isTranslucent; + } + + public void setReplacedDuringPlacement(boolean replacedDuringPlacement) { + this.replacedDuringPlacement = replacedDuringPlacement; + } + + @Override + public boolean hasContainer() { + return this.hasContainer; + } + + public void setHasContainer(boolean hasContainer) { + this.hasContainer = hasContainer; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java b/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java new file mode 100644 index 0000000..fc7c36c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.registry; + +public class SimpleItemMaterial implements ItemMaterial { + + private final int maxStackSize; + private final int maxDamage; + + public SimpleItemMaterial(int maxStackSize, int maxDamage) { + this.maxStackSize = maxStackSize; + this.maxDamage = maxDamage; + } + + @Override + public int getMaxStackSize() { + return maxStackSize; + } + + @Override + public int getMaxDamage() { + return maxDamage; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/InvalidSnapshotException.java b/src/main/java/com/sk89q/worldedit/world/snapshot/InvalidSnapshotException.java new file mode 100644 index 0000000..8edb4f7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/InvalidSnapshotException.java @@ -0,0 +1,24 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot; + +public class InvalidSnapshotException extends Exception { + +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/ModificationTimerParser.java b/src/main/java/com/sk89q/worldedit/world/snapshot/ModificationTimerParser.java new file mode 100644 index 0000000..ed2f4a5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/ModificationTimerParser.java @@ -0,0 +1,35 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot; + +import java.io.File; +import java.util.Calendar; +import java.util.GregorianCalendar; + +public class ModificationTimerParser implements SnapshotDateParser { + + @Override + public Calendar detectDate(File file) { + Calendar cal = new GregorianCalendar(); + cal.setTimeInMillis(file.lastModified()); + return cal; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java b/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java new file mode 100644 index 0000000..53f3105 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java @@ -0,0 +1,220 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.world.snapshot; + +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.storage.*; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.time.ZonedDateTime; +import java.util.Locale; +import java.util.zip.ZipFile; + +/** + * A snapshot is a backup. + */ +public class Snapshot implements Comparable { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + protected File file; + protected String name; + protected ZonedDateTime date; + + /** + * Construct a snapshot restoration operation. + * + * @param repo a repository + * @param snapshot a snapshot name + */ + public Snapshot(SnapshotRepository repo, String snapshot) { + file = new File(repo.getDirectory(), snapshot); + name = snapshot; + } + + /** + * Get a chunk store. + * + * @return a chunk store + * @throws IOException if there is an error loading the chunk store + * @throws DataException if there is an error loading the chunk store + */ + public ChunkStore getChunkStore() throws IOException, DataException { + ChunkStore chunkStore = internalGetChunkStore(); + + LOGGER.info("WorldEdit: Using " + chunkStore.getClass().getCanonicalName() + + " for loading snapshot '" + file.getAbsolutePath() + "'"); + + return chunkStore; + } + + /** + * Get a chunk store. + * + * @return a chunk store + * @throws IOException if there is an error loading the chunk store + * @throws DataException if there is an error loading the chunk store + */ + private ChunkStore internalGetChunkStore() throws IOException, DataException { + String lowerCaseFileName = file.getName().toLowerCase(Locale.ROOT); + if (lowerCaseFileName.endsWith(".zip")) { + try { + ChunkStore chunkStore = new TrueZipMcRegionChunkStore(file); + + if (!chunkStore.isValid()) { + return new TrueZipLegacyChunkStore(file); + } + + return chunkStore; + } catch (NoClassDefFoundError e) { + ChunkStore chunkStore = new ZippedMcRegionChunkStore(file); + + if (!chunkStore.isValid()) { + return new ZippedLegacyChunkStore(file); + } + + return chunkStore; + } + } else if (lowerCaseFileName.endsWith(".tar.bz2") + || lowerCaseFileName.endsWith(".tar.gz") + || lowerCaseFileName.endsWith(".tar")) { + try { + ChunkStore chunkStore = new TrueZipMcRegionChunkStore(file); + + if (!chunkStore.isValid()) { + return new TrueZipLegacyChunkStore(file); + } + + return chunkStore; + } catch (NoClassDefFoundError e) { + throw new DataException("TrueZIP is required for .tar support"); + } + } else { + ChunkStore chunkStore = new FileMcRegionChunkStore(file); + + if (!chunkStore.isValid()) { + return new FileLegacyChunkStore(file); + } + + return chunkStore; + } + } + + /** + * Check the zip/tar file it contains the given world. + * + * @return true if the zip/tar file contains the given world + */ + public boolean containsWorld(String worldname) { + try { + String lowerCaseFileName = file.getName().toLowerCase(Locale.ROOT); + if (lowerCaseFileName.endsWith(".zip")) { + try (ZipFile entry = new ZipFile(file)) { + return (entry.getEntry(worldname) != null + || entry.getEntry(worldname + "/level.dat") != null); + } + } else if (lowerCaseFileName.endsWith(".tar.bz2") + || lowerCaseFileName.endsWith(".tar.gz") + || lowerCaseFileName.endsWith(".tar")) { + try { + de.schlichtherle.util.zip.ZipFile entry = new de.schlichtherle.util.zip.ZipFile(file); + + return entry.getEntry(worldname) != null; + } catch (NoClassDefFoundError e) { + throw new DataException("TrueZIP is required for .tar support"); + } + } else { + return (file.getName().equalsIgnoreCase(worldname)); + } + } catch (IOException ex) { + // Skip the file, but print an error + LOGGER.info("Could not load snapshot: " + + file.getPath()); + } catch (DataException ex) { + // No truezip, so tar file not supported. + // Dont print, just skip the file. + } + return false; + } + + /** + * Get the snapshot's name. + * + * @return the name of the snapshot + */ + public String getName() { + return name; + } + + /** + * Get the file for the snapshot. + * + * @return path to the snapshot + */ + public File getFile() { + return file; + } + + /** + * Get the date associated with this snapshot. + * + * @return date for the snapshot + */ + public ZonedDateTime getDate() { + return date; + } + + /** + * Set the date of the snapshot. + * + * @param date the date of the snapshot + */ + public void setDate(ZonedDateTime date) { + this.date = date; + } + + @Override + public int compareTo(Snapshot o) { + if (o.date == null || date == null) { + // Remove the folder from the name + int ourIndex = name.indexOf('/'); + int theirIndex = o.name.indexOf('/'); + return name.substring(Math.min(ourIndex, 0)) + .compareTo(o.name.substring(Math.min(theirIndex, 0))); + } else { + return date.compareTo(o.date); + } + } + + @Override + public boolean equals(Object o) { + return o instanceof Snapshot && file.equals(((Snapshot) o).file); + } + + @Override + public int hashCode() { + return file.hashCode(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotDateParser.java b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotDateParser.java new file mode 100644 index 0000000..06ce0cc --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotDateParser.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot; + +import java.io.File; +import java.util.Calendar; +import javax.annotation.Nullable; + +/** + * A name parser attempts to make sense of a filename for a snapshot. + */ +public interface SnapshotDateParser { + + /** + * Attempt to detect a date from a file. + * + * @param file the file + * @return date or null + */ + @Nullable + Calendar detectDate(File file); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java new file mode 100644 index 0000000..48d369a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java @@ -0,0 +1,245 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.world.snapshot; + +import com.sk89q.worldedit.world.storage.MissingWorldException; + +import javax.annotation.Nullable; +import java.io.File; +import java.io.FilenameFilter; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.*; + +/** + * A repository contains zero or more snapshots. + */ +public class SnapshotRepository { + + protected File dir; + protected List dateParsers = new ArrayList<>(); + + /** + * Create a new instance of a repository. + * + * @param dir the directory + */ + public SnapshotRepository(File dir) { + this.dir = dir; + + // If folder doesn't exist, make it + dir.mkdirs(); + + dateParsers.add(new YYMMDDHHIISSParser()); + dateParsers.add(new ModificationTimerParser()); + } + + /** + * Create a new instance of a repository. + * + * @param dir the directory + */ + public SnapshotRepository(String dir) { + this(new File(dir)); + } + + /** + * Get a list of snapshots in a directory. The newest snapshot is + * near the top of the array. + * + * @param newestFirst true to get the newest first + * @return a list of snapshots + */ + public List getSnapshots(boolean newestFirst, String worldName) throws MissingWorldException { + FilenameFilter filter = (dir, name) -> { + File f = new File(dir, name); + return isValidSnapshot(f); + }; + + File[] snapshotFiles = dir.listFiles(); + if (snapshotFiles == null) { + throw new MissingWorldException(worldName); + } + List list = new ArrayList<>(snapshotFiles.length); + + for (File file : snapshotFiles) { + if (isValidSnapshot(file)) { + Snapshot snapshot = new Snapshot(this, file.getName()); + if (snapshot.containsWorld(worldName)) { + detectDate(snapshot); + list.add(snapshot); + } + } else if (file.isDirectory() && file.getName().equalsIgnoreCase(worldName)) { + for (String name : file.list(filter)) { + Snapshot snapshot = new Snapshot(this, file.getName() + "/" + name); + detectDate(snapshot); + list.add(snapshot); + } + } + } + + if (newestFirst) { + list.sort(Collections.reverseOrder()); + } else { + Collections.sort(list); + } + + return list; + } + + /** + * Get the first snapshot after a date. + * + * @param date a date + * @return a snapshot or null + */ + @Nullable + public Snapshot getSnapshotAfter(ZonedDateTime date, String world) throws MissingWorldException { + List snapshots = getSnapshots(true, world); + Snapshot last = null; + + for (Snapshot snapshot : snapshots) { + if (snapshot.getDate() != null && snapshot.getDate().compareTo(date) < 0) { + return last; + } + + last = snapshot; + } + + return last; + } + + /** + * Get the first snapshot before a date. + * + * @param date a date + * @return a snapshot or null + */ + @Nullable + public Snapshot getSnapshotBefore(ZonedDateTime date, String world) throws MissingWorldException { + List snapshots = getSnapshots(false, world); + Snapshot last = null; + + for (Snapshot snapshot : snapshots) { + if (snapshot.getDate().compareTo(date) > 0) { + return last; + } + + last = snapshot; + } + + return last; + } + + /** + * Attempt to detect a snapshot's date and assign it. + * + * @param snapshot the snapshot + */ + protected void detectDate(Snapshot snapshot) { + for (SnapshotDateParser parser : dateParsers) { + Calendar date = parser.detectDate(snapshot.getFile()); + if (date != null) { + snapshot.setDate(date.toInstant().atZone(ZoneOffset.UTC)); + return; + } + } + + snapshot.setDate(null); + } + + /** + * Get the default snapshot. + * + * @param world the world name + * @return a snapshot or null + */ + @Nullable + public Snapshot getDefaultSnapshot(String world) throws MissingWorldException { + List snapshots = getSnapshots(true, world); + + if (snapshots.isEmpty()) { + return null; + } + + return snapshots.get(0); + } + + /** + * Check to see if a snapshot is valid. + * + * @param snapshot a snapshot name + * @return whether it is a valid snapshot + */ + public boolean isValidSnapshotName(String snapshot) { + return isValidSnapshot(new File(dir, snapshot)); + } + + /** + * Check to see if a snapshot is valid. + * + * @param file the file to the snapshot + * @return whether it is a valid snapshot + */ + protected boolean isValidSnapshot(File file) { + if (!file.getName().matches("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+$")) { + return false; + } + + if (file.isDirectory() && new File(file, "level.dat").exists()) { + return true; + } + if (file.isFile()) { + String lowerCaseFileName = file.getName().toLowerCase(Locale.ROOT); + return lowerCaseFileName.endsWith(".zip") + || lowerCaseFileName.endsWith(".tar.bz2") + || lowerCaseFileName.endsWith(".tar.gz") + || lowerCaseFileName.endsWith(".tar"); + } + return false; + } + + /** + * Get a snapshot. + * + * @param name the name of the snapshot + * @return a snapshot + * @throws InvalidSnapshotException if the snapshot is invalid + */ + public Snapshot getSnapshot(String name) throws InvalidSnapshotException { + if (!isValidSnapshotName(name)) { + throw new InvalidSnapshotException(); + } + + return new Snapshot(this, name); + } + + /** + * Get the snapshot directory. + * + * @return a path + */ + public File getDirectory() { + return dir; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java new file mode 100644 index 0000000..b6b9460 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java @@ -0,0 +1,202 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.chunk.Chunk; +import com.sk89q.worldedit.world.storage.ChunkStore; +import com.sk89q.worldedit.world.storage.MissingChunkException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * A snapshot restore operation. + */ +public class SnapshotRestore { + + private final Map> neededChunks = new LinkedHashMap<>(); + private final ChunkStore chunkStore; + private final EditSession editSession; + private ArrayList missingChunks; + private ArrayList errorChunks; + private String lastErrorMessage; + + /** + * Construct the snapshot restore operation. + * + * @param chunkStore The {@link ChunkStore} to restore from + * @param editSession The {@link EditSession} to restore to + * @param region The {@link Region} to restore to + */ + public SnapshotRestore(ChunkStore chunkStore, EditSession editSession, Region region) { + this.chunkStore = chunkStore; + this.editSession = editSession; + + if (region instanceof CuboidRegion) { + findNeededCuboidChunks(region); + } else { + findNeededChunks(region); + } + } + + /** + * Find needed chunks in the axis-aligned bounding box of the region. + * + * @param region The {@link Region} to iterate + */ + private void findNeededCuboidChunks(Region region) { + BlockVector3 min = region.getMinimumPoint(); + BlockVector3 max = region.getMaximumPoint(); + + // First, we need to group points by chunk so that we only need + // to keep one chunk in memory at any given moment + for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { + for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { + BlockVector3 pos = BlockVector3.at(x, y, z); + checkAndAddBlock(pos); + } + } + } + } + + /** + * Find needed chunks in the region. + * + * @param region The {@link Region} to iterate + */ + private void findNeededChunks(Region region) { + // First, we need to group points by chunk so that we only need + // to keep one chunk in memory at any given moment + for (BlockVector3 pos : region) { + checkAndAddBlock(pos); + } + } + + private void checkAndAddBlock(BlockVector3 pos) { + if (editSession.getMask() != null && !editSession.getMask().test(pos)) { + return; + } + + BlockVector2 chunkPos = ChunkStore.toChunk(pos); + + // Unidentified chunk + if (!neededChunks.containsKey(chunkPos)) { + neededChunks.put(chunkPos, new ArrayList<>()); + } + + neededChunks.get(chunkPos).add(pos); + } + + /** + * Get the number of chunks that are needed. + * + * @return a number of chunks + */ + public int getChunksAffected() { + return neededChunks.size(); + } + + /** + * Restores to world. + * + * @throws MaxChangedBlocksException if the max block change limit is exceeded + */ + public void restore() throws MaxChangedBlocksException { + + missingChunks = new ArrayList<>(); + errorChunks = new ArrayList<>(); + + // Now let's start restoring! + for (Map.Entry> entry : neededChunks.entrySet()) { + BlockVector2 chunkPos = entry.getKey(); + Chunk chunk; + + try { + chunk = chunkStore.getChunk(chunkPos, editSession.getWorld()); + // Good, the chunk could be at least loaded + + // Now just copy blocks! + for (BlockVector3 pos : entry.getValue()) { + try { + editSession.setBlock(pos, chunk.getBlock(pos)); + } catch (DataException e) { + // this is a workaround: just ignore for now + } + } + } catch (MissingChunkException me) { + missingChunks.add(chunkPos); + } catch (IOException | DataException me) { + errorChunks.add(chunkPos); + lastErrorMessage = me.getMessage(); + } + } + } + + /** + * Get a list of the missing chunks. restore() must have been called + * already. + * + * @return a list of coordinates + */ + public List getMissingChunks() { + return missingChunks; + } + + /** + * Get a list of the chunks that could not have been loaded for other + * reasons. restore() must have been called already. + * + * @return a list of coordinates + */ + public List getErrorChunks() { + return errorChunks; + } + + /** + * Checks to see where the backup succeeded in any capacity. False will + * be returned if no chunk could be successfully loaded. + * + * @return true if there was total failure + */ + public boolean hadTotalFailure() { + return missingChunks.size() + errorChunks.size() == getChunksAffected(); + } + + /** + * Get the last error message. + * + * @return a message + */ + public String getLastErrorMessage() { + return lastErrorMessage; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java b/src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java new file mode 100644 index 0000000..49a8269 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java @@ -0,0 +1,51 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot; + +import java.io.File; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class YYMMDDHHIISSParser implements SnapshotDateParser { + + private final Pattern datePattern = + Pattern.compile("([0-9]+)[^0-9]?([0-9]+)[^0-9]?([0-9]+)[^0-9]?" + + "([0-9]+)[^0-9]?([0-9]+)[^0-9]?([0-9]+)(\\..*)?"); + + @Override + public Calendar detectDate(File file) { + Matcher matcher = datePattern.matcher(file.getName()); + if (matcher.matches()) { + int year = Integer.parseInt(matcher.group(1)); + int month = Integer.parseInt(matcher.group(2)); + int day = Integer.parseInt(matcher.group(3)); + int hrs = Integer.parseInt(matcher.group(4)); + int min = Integer.parseInt(matcher.group(5)); + int sec = Integer.parseInt(matcher.group(6)); + Calendar calender = new GregorianCalendar(); + calender.set(year, month, day, hrs, min, sec); + return calender; + } + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/Snapshot.java b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/Snapshot.java new file mode 100644 index 0000000..624c31f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/Snapshot.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot.experimental; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.chunk.Chunk; +import com.sk89q.worldedit.world.storage.ChunkStoreHelper; + +import java.io.Closeable; +import java.io.IOException; + +/** + * Represents a world snapshot. + */ +public interface Snapshot extends Closeable { + + SnapshotInfo getInfo(); + + /** + * Get the chunk information for the given position. Implementations may ignore the Y-chunk + * if its chunks are only stored in 2D. + * + * @param position the position of the chunk + * @return the tag containing chunk data + */ + CompoundTag getChunkTag(BlockVector3 position) throws DataException, IOException; + + /** + * Get the chunk information for the given position. + * + * @see #getChunkTag(BlockVector3) + * @see ChunkStoreHelper#getChunk(CompoundTag) + */ + default Chunk getChunk(BlockVector3 position) throws DataException, IOException { + return ChunkStoreHelper.getChunk(getChunkTag(position)); + } + + /** + * Close this snapshot. This releases the IO handles used to load chunk information. + */ + @Override + void close() throws IOException; +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotComparator.java b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotComparator.java new file mode 100644 index 0000000..d2d76ee --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotComparator.java @@ -0,0 +1,35 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot.experimental; + +import java.util.Comparator; + +public class SnapshotComparator { + + private static final Comparator COMPARATOR = + Comparator.comparing(Snapshot::getInfo); + + public static Comparator getInstance() { + return COMPARATOR; + } + + private SnapshotComparator() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotDatabase.java b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotDatabase.java new file mode 100644 index 0000000..d12f416 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotDatabase.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot.experimental; + +import java.io.IOException; +import java.net.URI; +import java.time.ZonedDateTime; +import java.util.Optional; +import java.util.stream.Stream; + +import static com.sk89q.worldedit.util.collection.MoreStreams.takeWhile; + +/** + * Handler for querying snapshot storage. + */ +public interface SnapshotDatabase { + + /** + * Get the URI scheme handled by this database. + */ + String getScheme(); + + /** + * Get a snapshot by name. + * + * @param name the name of the snapshot + * @return the snapshot if available + */ + Optional getSnapshot(URI name) throws IOException; + + /** + * Get all snapshots by world, unsorted. The stream should be + * {@linkplain Stream#close() closed}, as it may allocate filesystem or network resources. + * + * @param worldName the name of the world + * @return a stream of all snapshots for the given world in this database + */ + Stream getSnapshots(String worldName) throws IOException; + + default Stream getSnapshotsNewestFirst(String worldName) throws IOException { + return getSnapshots(worldName).sorted(SnapshotComparator.getInstance().reversed()); + } + + default Stream getSnapshotsOldestFirst(String worldName) throws IOException { + return getSnapshots(worldName).sorted(SnapshotComparator.getInstance()); + } + + default Stream getSnapshotsBefore(String worldName, ZonedDateTime date) throws IOException { + return takeWhile( + // sorted from oldest -> newest, so all `before` are at the front + getSnapshotsOldestFirst(worldName), + snap -> snap.getInfo().getDateTime().isBefore(date) + ); + } + + default Stream getSnapshotsAfter(String worldName, ZonedDateTime date) throws IOException { + return takeWhile( + // sorted from newest -> oldest, so all `after` are at the front + getSnapshotsNewestFirst(worldName), + snap -> snap.getInfo().getDateTime().isAfter(date) + ); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotInfo.java b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotInfo.java new file mode 100644 index 0000000..5a8b969 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotInfo.java @@ -0,0 +1,94 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot.experimental; + +import com.google.common.collect.ComparisonChain; + +import java.net.URI; +import java.time.ZonedDateTime; +import java.util.Objects; + +/** + * Information about a snapshot, such as name and date. + */ +public final class SnapshotInfo implements Comparable { + + public static SnapshotInfo create(URI name, ZonedDateTime dateTime) { + return new SnapshotInfo(name, dateTime); + } + + private final URI name; + private final ZonedDateTime dateTime; + + private SnapshotInfo(URI name, ZonedDateTime dateTime) { + this.name = name; + this.dateTime = dateTime; + } + + public URI getName() { + return name; + } + + public String getDisplayName() { + if (name.getScheme().equals("snapfs")) { + // Stored raw as the scheme specific part + return name.getSchemeSpecificPart(); + } + return name.toString(); + } + + public ZonedDateTime getDateTime() { + return dateTime; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SnapshotInfo that = (SnapshotInfo) o; + return Objects.equals(name, that.name) + && Objects.equals(dateTime, that.dateTime); + } + + @Override + public int hashCode() { + return Objects.hash(name, dateTime); + } + + @Override + public String toString() { + return "SnapshotInfo{" + + "name='" + name + '\'' + + ",date=" + dateTime + + '}'; + } + + @Override + public int compareTo(SnapshotInfo o) { + return ComparisonChain.start() + .compare(dateTime, o.dateTime) + .compare(name, o.name) + .result(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java new file mode 100644 index 0000000..9d1f152 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java @@ -0,0 +1,203 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot.experimental; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.chunk.Chunk; +import com.sk89q.worldedit.world.storage.ChunkStore; +import com.sk89q.worldedit.world.storage.MissingChunkException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * A snapshot restore operation. + */ +public class SnapshotRestore { + + private final Map> neededChunks = new LinkedHashMap<>(); + private final Snapshot snapshot; + private final EditSession editSession; + private ArrayList missingChunks; + private ArrayList errorChunks; + private String lastErrorMessage; + + /** + * Construct the snapshot restore operation. + * + * @param snapshot The {@link Snapshot} to restore from + * @param editSession The {@link EditSession} to restore to + * @param region The {@link Region} to restore to + */ + public SnapshotRestore(Snapshot snapshot, EditSession editSession, Region region) { + this.snapshot = snapshot; + this.editSession = editSession; + + if (region instanceof CuboidRegion) { + findNeededCuboidChunks(region); + } else { + findNeededChunks(region); + } + } + + /** + * Find needed chunks in the axis-aligned bounding box of the region. + * + * @param region The {@link Region} to iterate + */ + private void findNeededCuboidChunks(Region region) { + BlockVector3 min = region.getMinimumPoint(); + BlockVector3 max = region.getMaximumPoint(); + + // First, we need to group points by chunk so that we only need + // to keep one chunk in memory at any given moment + for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { + for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { + BlockVector3 pos = BlockVector3.at(x, y, z); + checkAndAddBlock(pos); + } + } + } + } + + /** + * Find needed chunks in the region. + * + * @param region The {@link Region} to iterate + */ + private void findNeededChunks(Region region) { + // First, we need to group points by chunk so that we only need + // to keep one chunk in memory at any given moment + for (BlockVector3 pos : region) { + checkAndAddBlock(pos); + } + } + + private void checkAndAddBlock(BlockVector3 pos) { + if (editSession.getMask() != null && !editSession.getMask().test(pos)) { + return; + } + + BlockVector2 chunkPos = ChunkStore.toChunk(pos); + + // Unidentified chunk + if (!neededChunks.containsKey(chunkPos)) { + neededChunks.put(chunkPos, new ArrayList<>()); + } + + neededChunks.get(chunkPos).add(pos); + } + + /** + * Get the number of chunks that are needed. + * + * @return a number of chunks + */ + public int getChunksAffected() { + return neededChunks.size(); + } + + /** + * Restores to world. + * + * @throws MaxChangedBlocksException if the max block change limit is exceeded + */ + public void restore() throws MaxChangedBlocksException { + + missingChunks = new ArrayList<>(); + errorChunks = new ArrayList<>(); + + // Now let's start restoring! + for (Map.Entry> entry : neededChunks.entrySet()) { + BlockVector2 chunkPos = entry.getKey(); + Chunk chunk; + + try { + // This will need to be changed if we start officially supporting 3d snapshots. + chunk = snapshot.getChunk(chunkPos.toBlockVector3()); + // Good, the chunk could be at least loaded + + // Now just copy blocks! + for (BlockVector3 pos : entry.getValue()) { + try { + editSession.setBlock(pos, chunk.getBlock(pos)); + } catch (DataException e) { + // this is a workaround: just ignore for now + } + } + } catch (MissingChunkException me) { + missingChunks.add(chunkPos); + } catch (IOException | DataException me) { + errorChunks.add(chunkPos); + lastErrorMessage = me.getMessage(); + } + } + } + + /** + * Get a list of the missing chunks. restore() must have been called + * already. + * + * @return a list of coordinates + */ + public List getMissingChunks() { + return missingChunks; + } + + /** + * Get a list of the chunks that could not have been loaded for other + * reasons. restore() must have been called already. + * + * @return a list of coordinates + */ + public List getErrorChunks() { + return errorChunks; + } + + /** + * Checks to see where the backup succeeded in any capacity. False will + * be returned if no chunk could be successfully loaded. + * + * @return true if there was total failure + */ + public boolean hadTotalFailure() { + return missingChunks.size() + errorChunks.size() == getChunksAffected(); + } + + /** + * Get the last error message. + * + * @return a message + */ + public String getLastErrorMessage() { + return lastErrorMessage; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/fs/FileSystemSnapshotDatabase.java b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/fs/FileSystemSnapshotDatabase.java new file mode 100644 index 0000000..5980a17 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/fs/FileSystemSnapshotDatabase.java @@ -0,0 +1,295 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot.experimental.fs; + +import com.google.common.collect.ImmutableList; +import com.google.common.net.UrlEscapers; +import com.sk89q.worldedit.util.function.IOFunction; +import com.sk89q.worldedit.util.function.IORunnable; +import com.sk89q.worldedit.util.io.Closer; +import com.sk89q.worldedit.util.io.file.ArchiveDir; +import com.sk89q.worldedit.util.io.file.ArchiveNioSupport; +import com.sk89q.worldedit.util.io.file.MorePaths; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.util.time.FileNameDateTimeParser; +import com.sk89q.worldedit.util.time.ModificationDateTimeParser; +import com.sk89q.worldedit.util.time.SnapshotDateTimeParser; +import com.sk89q.worldedit.world.snapshot.experimental.Snapshot; +import com.sk89q.worldedit.world.snapshot.experimental.SnapshotDatabase; +import com.sk89q.worldedit.world.snapshot.experimental.SnapshotInfo; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.ZonedDateTime; +import java.util.*; +import java.util.stream.Stream; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Implements a snapshot database based on a filesystem. + */ +public class FileSystemSnapshotDatabase implements SnapshotDatabase { + + private static final String SCHEME = "snapfs"; + + private static final List DATE_TIME_PARSERS = + new ImmutableList.Builder() + .add(FileNameDateTimeParser.getInstance()) + .addAll(ServiceLoader.load(SnapshotDateTimeParser.class)) + .add(ModificationDateTimeParser.getInstance()) + .build(); + + public static ZonedDateTime tryParseDate(Path path) { + return tryParseDateInternal(path) + .orElseThrow(() -> new IllegalStateException("Could not detect date of " + path)); + } + + private static Optional tryParseDateInternal(Path path) { + return DATE_TIME_PARSERS.stream() + .map(parser -> parser.detectDateTime(path)) + .filter(Objects::nonNull) + .findFirst(); + } + + public static URI createUri(String name) { + return URI.create(SCHEME + ":" + UrlEscapers.urlFragmentEscaper().escape(name)); + } + + public static FileSystemSnapshotDatabase maybeCreate( + Path root, + ArchiveNioSupport archiveNioSupport + ) throws IOException { + Files.createDirectories(root); + return new FileSystemSnapshotDatabase(root, archiveNioSupport); + } + + private final Path root; + private final ArchiveNioSupport archiveNioSupport; + + public FileSystemSnapshotDatabase(Path root, ArchiveNioSupport archiveNioSupport) { + checkArgument(Files.isDirectory(root), "Database root is not a directory"); + try { + this.root = root.toRealPath(); + } catch (IOException e) { + throw new RuntimeException("Failed to resolve snapshot database path", e); + } + this.archiveNioSupport = archiveNioSupport; + } + + /* + * When this code says "idPath" it is the path that uniquely identifies that snapshot. + * A snapshot can be looked up by its idPath. + * + * When the code says "ioPath" it is the path that holds the world data, and can actually + * be read from proper. The "idPath" may not even exist, it is purely for the path components + * and not for IO. + */ + + private SnapshotInfo createSnapshotInfo(Path idPath, Path ioPath) { + // Try ID for parsing out of file name, IO for parsing mod time. + ZonedDateTime date = tryParseDateInternal(idPath).orElseGet(() -> tryParseDate(ioPath)); + return SnapshotInfo.create(createUri(idPath.toString()), date); + } + + private Snapshot createSnapshot(Path idPath, Path ioPath, @Nullable Closer closeCallback) { + return new FolderSnapshot( + createSnapshotInfo(idPath, ioPath), ioPath, closeCallback + ); + } + + public Path getRoot() { + return root; + } + + @Override + public String getScheme() { + return SCHEME; + } + + @Override + public Optional getSnapshot(URI name) throws IOException { + if (!name.getScheme().equals(SCHEME)) { + return Optional.empty(); + } + return getSnapshot(name.getSchemeSpecificPart()); + } + + private Optional getSnapshot(String id) throws IOException { + Path rawResolved = root.resolve(id); + // Catch trickery with paths: + Path ioPath = rawResolved.normalize(); + if (!ioPath.startsWith(root)) { + return Optional.empty(); + } + Path idPath = root.relativize(ioPath); + Optional result = tryRegularFileSnapshot(idPath); + if (result.isPresent()) { + return result; + } + if (!Files.isDirectory(ioPath)) { + return Optional.empty(); + } + return Optional.of(createSnapshot(idPath, ioPath, null)); + } + + private Optional tryRegularFileSnapshot(Path idPath) throws IOException { + Closer closer = Closer.create(); + Path root = this.root; + Path relative = idPath; + Iterator iterator = null; + try { + while (true) { + if (iterator == null) { + iterator = MorePaths.iterPaths(relative).iterator(); + } + if (!iterator.hasNext()) { + closer.close(); + return Optional.empty(); + } + Path relativeNext = iterator.next(); + Path next = root.resolve(relativeNext); + if (!Files.isRegularFile(next)) { + // This will never be it. + continue; + } + Optional newRootOpt = archiveNioSupport.tryOpenAsDir(next); + if (newRootOpt.isPresent()) { + ArchiveDir archiveDir = newRootOpt.get(); + root = archiveDir.getPath(); + closer.register(archiveDir); + // Switch path to path inside the archive + relative = root.resolve(relativeNext.relativize(relative).toString()); + iterator = null; + // Check if it exists, if so open snapshot + if (Files.exists(relative)) { + return Optional.of(createSnapshot(idPath, relative, closer)); + } + // Otherwise, we may have more archives to open. + // Keep searching! + } + } + } catch (Throwable t) { + throw closer.rethrowAndClose(t); + } + } + + @Override + public Stream getSnapshots(String worldName) throws IOException { + /* + There are a few possible snapshot formats we accept: + - a world directory, identified by /level.dat + - a directory with the world name, but no level.dat + - inside must be a timestamped directory/archive, which then has one of the two world + formats inside of it! + - a world archive, identified by .ext + * does not need to have level.dat inside + - a timestamped directory, identified by , that can have + - the two world formats described above, inside the directory + - a timestamped archive, identified by .ext, that can have + - the same as timestamped directory, but inside the archive. + + All archives may have a root directory with the same name as the archive, + minus the extensions. Due to extension detection methods, this won't work properly + with some files, e.g. world.qux.zip/world.qux is invalid, but world.qux.zip/world isn't. + */ + return SafeFiles.noLeakFileList(root) + .flatMap(IOFunction.unchecked(entry -> { + String worldEntry = getWorldEntry(worldName, entry); + if (worldEntry != null) { + return Stream.of(worldEntry); + } + String fileName = SafeFiles.canonicalFileName(entry); + if (fileName.equals(worldName) + && Files.isDirectory(entry) + && !Files.exists(entry.resolve("level.dat"))) { + // world dir with timestamp entries + return listTimestampedEntries(worldName, entry) + .map(id -> worldName + "/" + id); + } + return getTimestampedEntries(worldName, entry); + })) + .map(IOFunction.unchecked(id -> + getSnapshot(id) + .orElseThrow(() -> + new AssertionError("Could not find discovered snapshot: " + id) + ) + )); + } + + private Stream listTimestampedEntries(String worldName, Path directory) throws IOException { + return SafeFiles.noLeakFileList(directory) + .flatMap(IOFunction.unchecked(entry -> getTimestampedEntries(worldName, entry))); + } + + private Stream getTimestampedEntries(String worldName, Path entry) throws IOException { + ZonedDateTime dateTime = FileNameDateTimeParser.getInstance().detectDateTime(entry); + if (dateTime == null) { + // nothing available at this path + return Stream.of(); + } + String fileName = SafeFiles.canonicalFileName(entry); + if (Files.isDirectory(entry)) { + // timestamped directory, find worlds inside + return listWorldEntries(worldName, entry) + .map(id -> fileName + "/" + id); + } + if (!Files.isRegularFile(entry)) { + // not an archive either? + return Stream.of(); + } + Optional asArchive = archiveNioSupport.tryOpenAsDir(entry); + if (asArchive.isPresent()) { + // timestamped archive + ArchiveDir dir = asArchive.get(); + return listWorldEntries(worldName, dir.getPath()) + .map(id -> fileName + "/" + id) + .onClose(IORunnable.unchecked(dir::close)); + } + return Stream.of(); + } + + private Stream listWorldEntries(String worldName, Path directory) throws IOException { + return SafeFiles.noLeakFileList(directory) + .map(IOFunction.unchecked(entry -> getWorldEntry(worldName, entry))) + .filter(Objects::nonNull); + } + + private String getWorldEntry(String worldName, Path entry) throws IOException { + String fileName = SafeFiles.canonicalFileName(entry); + if (fileName.equals(worldName) && Files.exists(entry.resolve("level.dat"))) { + // world directory + return worldName; + } + if (fileName.startsWith(worldName + ".") && Files.isRegularFile(entry)) { + Optional asArchive = archiveNioSupport.tryOpenAsDir(entry); + if (asArchive.isPresent()) { + // world archive + asArchive.get().close(); + return fileName; + } + } + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/fs/FolderSnapshot.java b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/fs/FolderSnapshot.java new file mode 100644 index 0000000..7a65910 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/fs/FolderSnapshot.java @@ -0,0 +1,162 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.snapshot.experimental.fs; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.io.Closer; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.snapshot.experimental.Snapshot; +import com.sk89q.worldedit.world.snapshot.experimental.SnapshotInfo; +import com.sk89q.worldedit.world.storage.*; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; +import java.util.zip.GZIPInputStream; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Snapshot based on a world folder. Extracts chunks from the region folder. + * + *

+ * Note that the Path can belong to another filesystem. This allows easy integration with + * zips due to Java's built-in zipfs support. + *

+ */ +public class FolderSnapshot implements Snapshot { + + /** + * Object used by {@code getRegionFolder(Path)} to indicate that the path does not exist. + */ + private static final Object NOT_FOUND_TOKEN = new Object(); + + private static Object getRegionFolder(Path folder) throws IOException { + Path regionDir = folder.resolve("region"); + if (Files.exists(regionDir)) { + checkState(Files.isDirectory(regionDir), "Region folder is actually a file"); + return regionDir; + } + // Might be in a DIM* folder + try (Stream paths = Files.list(folder)) { + Optional path = paths + .filter(Files::isDirectory) + .filter(p -> p.getFileName().toString().startsWith("DIM")) + .map(p -> p.resolve("region")) + .filter(Files::isDirectory) + .findFirst(); + if (path.isPresent()) { + return path.get(); + } + } + // Might be its own region folder, check if the appropriate files exist + try (Stream paths = Files.list(folder)) { + if (paths + .filter(Files::isRegularFile) + .anyMatch(p -> { + String fileName = p.getFileName().toString(); + return fileName.startsWith("r") + && (fileName.endsWith(".mca") || fileName.endsWith(".mcr")); + })) { + return folder; + } + } + return NOT_FOUND_TOKEN; + } + + private final SnapshotInfo info; + private final Path folder; + private final AtomicReference regionFolder = new AtomicReference<>(); + private final @Nullable Closer closeCallback; + + public FolderSnapshot(SnapshotInfo info, Path folder, @Nullable Closer closeCallback) { + this.info = info; + // This is required to force TrueVfs to properly resolve parents. + // Kinda odd, but whatever works. + this.folder = folder.toAbsolutePath(); + this.closeCallback = closeCallback; + } + + public Path getFolder() { + return folder; + } + + @Override + public SnapshotInfo getInfo() { + return info; + } + + private Optional getRegionFolder() throws IOException { + Object regFolder = regionFolder.get(); + if (regFolder == null) { + Object update = getRegionFolder(folder); + if (!regionFolder.compareAndSet(null, update)) { + // failed race, get existing value + regFolder = regionFolder.get(); + } else { + regFolder = update; + } + } + return regFolder == NOT_FOUND_TOKEN ? Optional.empty() : Optional.of((Path) regFolder); + } + + @Override + public CompoundTag getChunkTag(BlockVector3 position) throws DataException, IOException { + BlockVector2 pos = position.toBlockVector2(); + Optional regFolder = getRegionFolder(); + if (!regFolder.isPresent()) { + Path chunkFile = getFolder().resolve(LegacyChunkStore.getFilename(pos, "/")); + if (!Files.exists(chunkFile)) { + throw new MissingChunkException(); + } + return ChunkStoreHelper.readCompoundTag(() -> + new GZIPInputStream(Files.newInputStream(chunkFile)) + ); + } + Path regionFile = regFolder.get().resolve(McRegionChunkStore.getFilename(pos)); + if (!Files.exists(regionFile)) { + // Try mcr as well + regionFile = regionFile.resolveSibling( + regionFile.getFileName().toString().replace(".mca", ".mcr") + ); + if (!Files.exists(regionFile)) { + throw new MissingChunkException(); + } + } + try (InputStream stream = Files.newInputStream(regionFile)) { + McRegionReader regionReader = new McRegionReader(stream); + return ChunkStoreHelper.readCompoundTag(() -> regionReader.getChunkInputStream(pos)); + } + } + + @Override + public void close() throws IOException { + if (closeCallback != null) { + closeCallback.close(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/package-info.java b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/package-info.java new file mode 100644 index 0000000..273fbb9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/package-info.java @@ -0,0 +1,30 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +/** + * Experimental, in-testing, snapshot API. Do NOT rely on this API in plugin releases, as it will + * move to the existing snapshot package when testing is complete. + * + *

+ * The existing snapshot API will be removed when this API is made official. It aims to have 100% + * compatibility with old snapshot storage, bar some odd date formats. + *

+ */ +package com.sk89q.worldedit.world.snapshot.experimental; +// TODO Un-experimentalize when ready. diff --git a/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java new file mode 100644 index 0000000..7123dce --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java @@ -0,0 +1,112 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.chunk.Chunk; + +import java.io.Closeable; +import java.io.IOException; + +/** + * Represents chunk storage mechanisms. + */ +public abstract class ChunkStore implements Closeable { + + /** + * The shift for converting to/from a chunk position. + * + *

+ * {@code >>} - to chunk + * {@code <<} - from chunk + *

+ */ + public static final int CHUNK_SHIFTS = 4; + + /** + * The shift for converting to/from a 3D chunk position. + * + *

+ * {@code >>} - to Y of 3D-chunk + * {@code <<} - from Y of 3D-chunk + *

+ */ + public static final int CHUNK_SHIFTS_Y = 8; + + /** + * Convert a position to a 3D-chunk. Y is counted in steps of 256. + * + * @param position the position + * @return chunk coordinates + */ + public static BlockVector3 toChunk3d(BlockVector3 position) { + return position.shr(CHUNK_SHIFTS, CHUNK_SHIFTS_Y, CHUNK_SHIFTS); + } + + /** + * Convert a position to a chunk. + * + * @param position the position + * @return chunk coordinates + */ + public static BlockVector2 toChunk(BlockVector3 position) { + return BlockVector2.at(position.getX() >> CHUNK_SHIFTS, position.getZ() >> CHUNK_SHIFTS); + } + + /** + * Get the tag for a chunk. + * + * @param position the position of the chunk + * @return tag + * @throws DataException thrown on data error + * @throws IOException thrown on I/O error + */ + public abstract CompoundTag getChunkTag(BlockVector2 position, World world) throws DataException, IOException; + + /** + * Get a chunk at a location. + * + * @param position the position of the chunk + * @return a chunk + * @throws ChunkStoreException thrown if there is an error from the chunk store + * @throws DataException thrown on data error + * @throws IOException thrown on I/O error + */ + public Chunk getChunk(BlockVector2 position, World world) throws DataException, IOException { + CompoundTag rootTag = getChunkTag(position, world); + return ChunkStoreHelper.getChunk(rootTag); + } + + @Override + public void close() throws IOException { + } + + /** + * Returns whether the chunk store is of this type. + * + * @return true if valid + */ + public abstract boolean isValid(); + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreException.java b/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreException.java new file mode 100644 index 0000000..f38d13a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreException.java @@ -0,0 +1,34 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; + +public class ChunkStoreException extends DataException { + + public ChunkStoreException(String msg) { + super(msg); + } + + public ChunkStoreException() { + super(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java b/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java new file mode 100644 index 0000000..224eb25 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java @@ -0,0 +1,131 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.chunk.*; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +public class ChunkStoreHelper { + + @FunctionalInterface + public interface ChunkDataInputSupplier { + + InputStream openInputStream() throws DataException, IOException; + + } + + public static CompoundTag readCompoundTag(ChunkDataInputSupplier input) throws DataException, IOException { + try (InputStream stream = input.openInputStream(); + NBTInputStream nbt = new NBTInputStream(stream)) { + Tag tag = nbt.readNamedTag().getTag(); + if (!(tag instanceof CompoundTag)) { + throw new ChunkStoreException("CompoundTag expected for chunk; got " + + tag.getClass().getName()); + } + + return (CompoundTag) tag; + } + } + + /** + * Convert a chunk NBT tag into a {@link Chunk} implementation. + * + * @param rootTag the root tag of the chunk + * @return a Chunk implementation + * @throws DataException if the rootTag is not valid chunk data + */ + public static Chunk getChunk(CompoundTag rootTag) throws DataException { + int dataVersion = rootTag.getInt("DataVersion"); + if (dataVersion == 0) { + dataVersion = -1; + } + + final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + final int currentDataVersion = platform.getDataVersion(); + if ((dataVersion > 0 || hasLevelSections(rootTag)) && dataVersion < currentDataVersion) { // only fix up MCA format, DFU doesn't support MCR chunks + final DataFixer dataFixer = platform.getDataFixer(); + if (dataFixer != null) { + rootTag = dataFixer.fixUp(DataFixer.FixTypes.CHUNK, rootTag, dataVersion); + dataVersion = currentDataVersion; + } + } + + if (dataVersion >= Constants.DATA_VERSION_MC_1_18) { + return new AnvilChunk18(rootTag); + } + + Map children = rootTag.getValue(); + CompoundTag tag = null; + + // Find Level tag + for (Map.Entry entry : children.entrySet()) { + if (entry.getKey().equals("Level")) { + if (entry.getValue() instanceof CompoundTag) { + tag = (CompoundTag) entry.getValue(); + break; + } else { + throw new ChunkStoreException("CompoundTag expected for 'Level'; got " + entry.getValue().getClass().getName()); + } + } + } + + if (tag == null) { + throw new ChunkStoreException("Missing root 'Level' tag"); + } + + if (dataVersion >= Constants.DATA_VERSION_MC_1_16) { + return new AnvilChunk16(tag); + } + if (dataVersion >= Constants.DATA_VERSION_MC_1_13) { + return new AnvilChunk13(tag); + } + + Map tags = tag.getValue(); + if (tags.containsKey("Sections")) { + return new AnvilChunk(tag); + } + + return new OldChunk(tag); + } + + private static boolean hasLevelSections(CompoundTag rootTag) { + Map children = rootTag.getValue(); + Tag levelTag = children.get("Level"); + if (levelTag instanceof CompoundTag) { + return ((CompoundTag) levelTag).getValue().containsKey("Sections"); + } + return false; + } + + private ChunkStoreHelper() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/FileLegacyChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/FileLegacyChunkStore.java new file mode 100644 index 0000000..3037d29 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/FileLegacyChunkStore.java @@ -0,0 +1,70 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +/** + * Represents the chunk store used by Minecraft Alpha. + */ +public class FileLegacyChunkStore extends LegacyChunkStore { + + private final File path; + + /** + * Create an instance. The passed path is the folder to read the + * chunk files from. + * + * @param path path to a folder + */ + public FileLegacyChunkStore(File path) { + this.path = path; + } + + /** + * Get the input stream for a chunk file. + * + * @param f1 the first part of the pathname + * @param f2 the second part of the pathname + * @param name the name of the file + * @return an input stream + * @throws DataException if there is an error getting data for this chunk + */ + @Override + protected InputStream getInputStream(String f1, String f2, String name) throws DataException { + String file = f1 + File.separator + f2 + File.separator + name; + try { + return new FileInputStream(new File(path, file)); + } catch (FileNotFoundException e) { + throw new MissingChunkException(); + } + } + + @Override + public boolean isValid() { + return true; // Yeah, oh well + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/FileMcRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/FileMcRegionChunkStore.java new file mode 100644 index 0000000..c821bb4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/FileMcRegionChunkStore.java @@ -0,0 +1,76 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; + +import java.io.*; +import java.util.regex.Pattern; + +public class FileMcRegionChunkStore extends McRegionChunkStore { + + private final File path; + + /** + * Create an instance. The passed path is the folder to read the + * chunk files from. + * + * @param path a path + */ + public FileMcRegionChunkStore(File path) { + this.path = path; + } + + @Override + protected InputStream getInputStream(String name, String world) throws IOException, DataException { + Pattern ext = Pattern.compile(".*\\.mc[ra]$"); // allow either file extension, both work the same + File file = null; + File[] files = new File(path, "region").listFiles(); + + if (files == null) { + throw new FileNotFoundException(); + } + + for (File f : files) { + String tempName = f.getName().replaceFirst("mcr$", "mca"); // matcher only does one at a time + if (ext.matcher(f.getName()).matches() && name.equalsIgnoreCase(tempName)) { + // get full original path now + file = new File(path + File.separator + "region" + File.separator + f.getName()); + break; + } + } + + try { + if (file == null) { + throw new FileNotFoundException(); + } + return new FileInputStream(file); + } catch (FileNotFoundException e) { + throw new MissingChunkException(); + } + } + + @Override + public boolean isValid() { + return new File(path, "region").isDirectory() + || new File(path, "DIM-1" + File.separator + "region").isDirectory(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/InvalidFormatException.java b/src/main/java/com/sk89q/worldedit/world/storage/InvalidFormatException.java new file mode 100644 index 0000000..5b66f71 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/InvalidFormatException.java @@ -0,0 +1,30 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; + +public class InvalidFormatException extends DataException { + + public InvalidFormatException(String msg) { + super(msg); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java new file mode 100644 index 0000000..69a531f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java @@ -0,0 +1,99 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.World; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.GZIPInputStream; + +/** + * Represents chunk stores that use Alpha's file format for storing chunks. + * The code to resolve the filename is already implemented in this class + * and an inheriting class merely needs to implement getInputStream(). + */ +public abstract class LegacyChunkStore extends ChunkStore { + + /** + * Get the filename of a chunk. + * + * @param position chunk position + * @param separator folder separator character + * @return pathname + */ + public static String getFilename(BlockVector2 position, String separator) { + int x = position.getBlockX(); + int z = position.getBlockZ(); + + String folder1 = Integer.toString(divisorMod(x, 64), 36); + String folder2 = Integer.toString(divisorMod(z, 64), 36); + String filename = "c." + Integer.toString(x, 36) + + "." + Integer.toString(z, 36) + ".dat"; + + return folder1 + separator + folder2 + separator + filename; + } + + /** + * Get the filename of a chunk, using the system's default path + * separator. + * + * @param position chunk position + * @return pathname + */ + public static String getFilename(BlockVector2 position) { + return getFilename(position, File.separator); + } + + @Override + public CompoundTag getChunkTag(BlockVector2 position, World world) throws DataException, IOException { + int x = position.getBlockX(); + int z = position.getBlockZ(); + + String folder1 = Integer.toString(divisorMod(x, 64), 36); + String folder2 = Integer.toString(divisorMod(z, 64), 36); + String filename = "c." + Integer.toString(x, 36) + + "." + Integer.toString(z, 36) + ".dat"; + + return ChunkStoreHelper.readCompoundTag(() -> + new GZIPInputStream(getInputStream(folder1, folder2, filename)) + ); + } + + private static int divisorMod(int a, int n) { + return (int) (a - n * Math.floor(Math.floor(a) / (double) n)); + } + + /** + * Get the input stream for a chunk file. + * + * @param f1 the first part of the path + * @param f2 the second part of the path + * @param name the name + * @return an input stream + * @throws IOException if there is an error getting the chunk data + */ + protected abstract InputStream getInputStream(String f1, String f2, String name) throws IOException, DataException; + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java new file mode 100644 index 0000000..4e28462 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.World; + +import java.io.IOException; +import java.io.InputStream; + +public abstract class McRegionChunkStore extends ChunkStore { + + protected String curFilename = null; + protected McRegionReader cachedReader = null; + + /** + * Get the filename of a region file. + * + * @param position chunk position + * @return the filename + */ + public static String getFilename(BlockVector2 position) { + int x = position.getBlockX(); + int z = position.getBlockZ(); + + return "r." + (x >> 5) + "." + (z >> 5) + ".mca"; + } + + protected McRegionReader getReader(BlockVector2 pos, String worldname) throws DataException, IOException { + String filename = getFilename(pos); + if (curFilename != null) { + if (curFilename.equals(filename)) { + return cachedReader; + } else { + try { + cachedReader.close(); + } catch (IOException ignored) { + } + } + } + InputStream stream = getInputStream(filename, worldname); + cachedReader = new McRegionReader(stream); + //curFilename = filename; + return cachedReader; + } + + @Override + public CompoundTag getChunkTag(BlockVector2 position, World world) throws DataException, IOException { + return ChunkStoreHelper.readCompoundTag(() -> { + McRegionReader reader = getReader(position, world.getName()); + + return reader.getChunkInputStream(position); + }); + } + + /** + * Get the input stream for a chunk file. + * + * @param name the name of the chunk file + * @param worldName the world name + * @return an input stream + * @throws IOException if there is an error getting the chunk data + */ + protected abstract InputStream getInputStream(String name, String worldName) throws IOException, DataException; + + @Override + public void close() throws IOException { + if (cachedReader != null) { + cachedReader.close(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java b/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java new file mode 100644 index 0000000..789bdc4 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java @@ -0,0 +1,193 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ +/* + + Region File Format + + Concept: The minimum unit of storage on hard drives is 4KB. 90% of Minecraft + chunks are smaller than 4KB. 99% are smaller than 8KB. Write a simple + container to store chunks in single files in runs of 4KB sectors. + + Each region file represents a 32x32 group of chunks. The conversion from + chunk number to region number is floor(coord / 32): a chunk at (30, -3) + would be in region (0, -1), and one at (70, -30) would be at (3, -1). + Region files are named "r.x.z.data", where x and z are the region coordinates. + + A region file begins with a 4KB header that describes where chunks are stored + in the file. A 4-byte big-endian integer represents sector offsets and sector + counts. The chunk offset for a chunk (x, z) begins at byte 4*(x+z*32) in the + file. The bottom byte of the chunk offset indicates the number of sectors the + chunk takes up, and the top 3 bytes represent the sector number of the chunk. + Given a chunk offset o, the chunk data begins at byte 4096*(o/256) and takes up + at most 4096*(o%256) bytes. A chunk cannot exceed 1MB in size. If a chunk + offset is 0, the corresponding chunk is not stored in the region file. + + Chunk data begins with a 4-byte big-endian integer representing the chunk data + length in bytes, not counting the length field. The length must be smaller than + 4096 times the number of sectors. The next byte is a version field, to allow + backwards-compatible updates to how chunks are encoded. + + A version of 1 represents a gzipped NBT file. The gzipped data is the chunk + length - 1. + + A version of 2 represents a deflated (zlib compressed) NBT file. The deflated + data is the chunk length - 1. + + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.util.io.ForwardSeekableInputStream; +import com.sk89q.worldedit.world.DataException; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.GZIPInputStream; +import java.util.zip.InflaterInputStream; + +/** + * Reader for a MCRegion file. This reader works on input streams, meaning + * that it can be used to read files from non-file based sources. + */ +public class McRegionReader { + + protected static final int VERSION_GZIP = 1; + protected static final int VERSION_DEFLATE = 2; + protected static final int SECTOR_BYTES = 4096; + protected static final int SECTOR_INTS = SECTOR_BYTES / 4; + public static final int CHUNK_HEADER_SIZE = 5; + + protected ForwardSeekableInputStream stream; + protected DataInputStream dataStream; + + protected int[] offsets; + + /** + * Construct the reader. + * + * @param stream the stream + * @throws IOException if there is an error getting the region data + */ + public McRegionReader(InputStream stream) throws IOException { + this.stream = new ForwardSeekableInputStream(stream); + this.dataStream = new DataInputStream(this.stream); + + readHeader(); + } + + /** + * Read the header. + * + * @throws IOException if there is an error getting the header data + */ + private void readHeader() throws IOException { + offsets = new int[SECTOR_INTS]; + + for (int i = 0; i < SECTOR_INTS; ++i) { + int offset = dataStream.readInt(); + offsets[i] = offset; + } + } + + /** + * Gets the uncompressed data input stream for a chunk. + * + * @param position chunk position + * @return an input stream + * @throws IOException if there is an error getting the chunk data + * @throws DataException if there is an error getting the chunk data + */ + public synchronized InputStream getChunkInputStream(BlockVector2 position) throws IOException, DataException { + int x = position.getBlockX() & 31; + int z = position.getBlockZ() & 31; + + int offset = getOffset(x, z); + + // The chunk hasn't been generated + if (offset == 0) { + throw new DataException("The chunk at " + position + " is not generated"); + } + + int sectorNumber = offset >> 8; + int numSectors = offset & 0xFF; + + stream.seek((long) sectorNumber * SECTOR_BYTES); + int length = dataStream.readInt(); + + if (length > SECTOR_BYTES * numSectors) { + throw new DataException("MCRegion chunk at " + + x + "," + z + " has an invalid length of " + length); + } + + byte version = dataStream.readByte(); + + if (version == VERSION_GZIP) { + byte[] data = new byte[length - 1]; + if (dataStream.read(data) < length - 1) { + throw new DataException("MCRegion file does not contain " + + x + "," + z + " in full"); + } + return new GZIPInputStream(new ByteArrayInputStream(data)); + } else if (version == VERSION_DEFLATE) { + byte[] data = new byte[length - 1]; + if (dataStream.read(data) < length - 1) { + throw new DataException("MCRegion file does not contain " + + x + "," + z + " in full"); + } + return new InflaterInputStream(new ByteArrayInputStream(data)); + } else { + throw new DataException("MCRegion chunk at " + + x + "," + z + " has an unsupported version of " + version); + } + } + + /** + * Get the offset for a chunk. May return 0 if it doesn't exist. + * + * @param x the X coordinate + * @param z the Z coordinate + * @return the offset + */ + private int getOffset(int x, int z) { + return offsets[x + z * 32]; + } + + /** + * Returns whether the file contains a chunk. + * + * @param x the X coordinate + * @param z the Z coordinate + * @return the offset + */ + public boolean hasChunk(int x, int z) { + return getOffset(x, z) != 0; + } + + /** + * Close the stream. + */ + public void close() throws IOException { + stream.close(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/MissingChunkException.java b/src/main/java/com/sk89q/worldedit/world/storage/MissingChunkException.java new file mode 100644 index 0000000..b44f11f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/MissingChunkException.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.math.Vector2; + +/** + * Thrown if a chunk is missing. + */ +public class MissingChunkException extends ChunkStoreException { + + private Vector2 position; + + public MissingChunkException() { + super(); + } + + public MissingChunkException(Vector2 position) { + super(); + this.position = position; + } + + /** + * Get chunk position in question. May be null if unknown. + * + * @return a chunk position + */ + public Vector2 getChunkPosition() { + return position; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/MissingWorldException.java b/src/main/java/com/sk89q/worldedit/world/storage/MissingWorldException.java new file mode 100644 index 0000000..047c967 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/MissingWorldException.java @@ -0,0 +1,54 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import javax.annotation.Nullable; + +/** + * Thrown if the world is missing. + */ +public class MissingWorldException extends ChunkStoreException { + + private String worldName; + + public MissingWorldException() { + super(); + } + + public MissingWorldException(String worldName) { + super(); + this.worldName = worldName; + } + + public MissingWorldException(String msg, String worldName) { + super(msg); + this.worldName = worldName; + } + + /** + * Get name of the world in question. May be null if unknown. + * + * @return the world name + */ + @Nullable + public String getWorldName() { + return worldName; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java b/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java new file mode 100644 index 0000000..b84feff --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java @@ -0,0 +1,58 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.jnbt.ListTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.Location; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Utility methods for working with NBT data used in Minecraft. + */ +public final class NBTConversions { + + private NBTConversions() { + } + + /** + * Read a {@code Location} from two list tags, the first of which contains + * three numbers for the X, Y, and Z components, and the second of + * which contains two numbers, the yaw and pitch in degrees. + * + *

For values that are unavailable, their values will be 0.

+ * + * @param extent the extent + * @param positionTag the position tag + * @param directionTag the direction tag + * @return a location + */ + public static Location toLocation(Extent extent, ListTag positionTag, ListTag directionTag) { + checkNotNull(extent); + checkNotNull(positionTag); + checkNotNull(directionTag); + return new Location( + extent, + positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), + directionTag.getFloat(0), directionTag.getFloat(1)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/TrueZipLegacyChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/TrueZipLegacyChunkStore.java new file mode 100644 index 0000000..fd083fa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/TrueZipLegacyChunkStore.java @@ -0,0 +1,158 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; +import de.schlichtherle.util.zip.ZipEntry; +import de.schlichtherle.util.zip.ZipFile; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.regex.Pattern; +import java.util.zip.ZipException; + +/** + * Represents the chunk store used by Minecraft alpha but zipped. Uses + * the replacement classes for java.util.zip.* from TrueZip. + */ +public class TrueZipLegacyChunkStore extends LegacyChunkStore { + + private final File zipFile; + private final ZipFile zip; + private String folder; + + /** + * Create an instance. The folder argument lets you choose a folder or + * path to look into in the ZIP for the files. Use a blank string for + * the folder to not look into a subdirectory. + * + * @param zipFile the ZIP file to open + * @param folder the folder to look into in the ZIP + * @throws IOException if there is an error opening the zip + * @throws ZipException if there is an error opening the zip + */ + public TrueZipLegacyChunkStore(File zipFile, String folder) throws IOException, ZipException { + this.zipFile = zipFile; + this.folder = folder; + + zip = new ZipFile(zipFile); + } + + /** + * Create an instance. The subf-older containing the chunk data will + * be detected. + * + * @param zipFile the ZIP file to open + * @throws IOException if there is an error opening the zip + * @throws ZipException if there is an error opening the zip + */ + public TrueZipLegacyChunkStore(File zipFile) throws IOException, ZipException { + this.zipFile = zipFile; + + zip = new ZipFile(zipFile); + } + + /** + * Get the input stream for a chunk file. + * + * @param f1 the first part of the filename + * @param f2 the second part of the filename + * @param name the name of the file + * @return an input stream + * @throws IOException if there is an error getting the chunk data + * @throws DataException if there is an error getting the chunk data + */ + @Override + @SuppressWarnings("unchecked") + protected InputStream getInputStream(String f1, String f2, String name) throws IOException, DataException { + String file = f1 + "/" + f2 + "/" + name; + + // Detect subfolder for the world's files + if (folder != null) { + if (!folder.isEmpty()) { + file = folder + "/" + file; + } + } else { + ZipEntry testEntry = zip.getEntry("level.dat"); + + // So, the data is not in the root directory + if (testEntry == null) { + // Let's try a world/ sub-directory + testEntry = getEntry("world/level.dat"); + + Pattern pattern = Pattern.compile(".*[\\\\/]level\\.dat$"); + + // So not there either... + if (testEntry == null) { + for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { + testEntry = e.nextElement(); + + // Whoo, found level.dat! + if (pattern.matcher(testEntry.getName()).matches()) { + folder = testEntry.getName().replaceAll("level\\.dat$", ""); + folder = folder.substring(0, folder.length() - 1); + file = folder + file; + break; + } + } + } else { + file = "world/" + file; + } + } + } + + ZipEntry entry = getEntry(file); + if (entry == null) { + throw new MissingChunkException(); + } + try { + return zip.getInputStream(entry); + } catch (ZipException e) { + throw new IOException("Failed to read " + file + " in ZIP"); + } + } + + /** + * Get an entry from the ZIP, trying both types of slashes. + * + * @param file the file + * @return an entry + */ + private ZipEntry getEntry(String file) { + ZipEntry entry = zip.getEntry(file); + if (entry != null) { + return entry; + } + return zip.getEntry(file.replace("/", "\\")); + } + + @Override + public void close() throws IOException { + zip.close(); + } + + @Override + public boolean isValid() { + return true; // Yeah, oh well + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java new file mode 100644 index 0000000..37e62e0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java @@ -0,0 +1,176 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; +import de.schlichtherle.util.zip.ZipEntry; +import de.schlichtherle.util.zip.ZipFile; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.regex.Pattern; +import java.util.zip.ZipException; + +/** + * Represents the chunk store used by Minecraft but zipped. Uses + * the replacement classes for java.util.zip.* from TrueZip. + */ +public class TrueZipMcRegionChunkStore extends McRegionChunkStore { + + protected File zipFile; + protected ZipFile zip; + protected String folder; + + /** + * Create an instance. The folder argument lets you choose a folder or + * path to look into in the ZIP for the files. Use a blank string for + * the folder to not look into a subdirectory. + * + * @param zipFile the ZIP file + * @param folder the folder to look into + * @throws IOException if there is an error opening the zip + * @throws ZipException if there is an error opening the zip + */ + public TrueZipMcRegionChunkStore(File zipFile, String folder) throws IOException, ZipException { + this.zipFile = zipFile; + this.folder = folder; + + zip = new ZipFile(zipFile); + } + + /** + * Create an instance. The subfolder containing the chunk data will + * be detected. + * + * @param zipFile the ZIP file + * @throws IOException if there is an error opening the zip + * @throws ZipException if there is an error opening the zip + */ + public TrueZipMcRegionChunkStore(File zipFile) throws IOException, ZipException { + this.zipFile = zipFile; + + zip = new ZipFile(zipFile); + } + + /** + * Get the input stream for a chunk file. + * + * @param name the name + * @param worldName the world name + * @return an input stream + * @throws IOException if there is an error getting the chunk data + * @throws DataException if there is an error getting the chunk data + */ + @Override + @SuppressWarnings("unchecked") + protected InputStream getInputStream(String name, String worldName) throws IOException, DataException { + // Detect subfolder for the world's files + if (folder != null) { + if (!folder.isEmpty()) { + name = folder + "/" + name; + } + } else { + Pattern pattern = Pattern.compile(".*\\.mc[ra]$"); + // World pattern + Pattern worldPattern = Pattern.compile(worldName + "[\\\\/].*"); + for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { + ZipEntry testEntry = e.nextElement(); + // Check for world + String entryName = testEntry.getName(); + if (worldPattern.matcher(entryName).matches()) { + // Check for file + if (pattern.matcher(entryName).matches()) { + int endIndex = entryName.lastIndexOf('/'); + if (endIndex < 0) { + endIndex = entryName.lastIndexOf('\\'); + } + folder = entryName.substring(0, endIndex); + if (folder.endsWith("poi") || folder.endsWith("entities")) { + continue; + } + name = folder + "/" + name; + break; + } + } + } + + // Check if world is found + if (folder == null) { + throw new MissingWorldException("Target world is not present in ZIP.", worldName); + } + } + + ZipEntry entry = getEntry(name); + if (entry == null) { + if (name.endsWith(".mca")) { // try old mcr format + entry = getEntry(name.replace(".mca", ".mcr")); + if (entry == null) { + throw new MissingChunkException(); + } + } else { + throw new MissingChunkException(); + } + } + try { + return zip.getInputStream(entry); + } catch (ZipException e) { + throw new IOException("Failed to read " + name + " in ZIP"); + } + } + + /** + * Get an entry from the ZIP, trying both types of slashes. + * + * @param file the file + * @return an entry + */ + private ZipEntry getEntry(String file) { + ZipEntry entry = zip.getEntry(file); + if (entry != null) { + return entry; + } + return zip.getEntry(file.replace("/", "\\")); + } + + @Override + public void close() throws IOException { + zip.close(); + } + + @Override + @SuppressWarnings("unchecked") + public boolean isValid() { + for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { + + ZipEntry testEntry = e.nextElement(); + + if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { + return true; + } + } + + return false; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/ZippedLegacyChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/ZippedLegacyChunkStore.java new file mode 100644 index 0000000..20a7ddb --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/ZippedLegacyChunkStore.java @@ -0,0 +1,153 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +/** + * Represents the chunk store used by Minecraft alpha but zipped. + */ +public class ZippedLegacyChunkStore extends LegacyChunkStore { + + private final ZipFile zip; + private String folder; + + /** + * Create an instance. The folder argument lets you choose a folder or + * path to look into in the ZIP for the files. Use a blank string for + * the folder to not look into a subdirectory. + * + * @param zipFile the zip file + * @param folder the folder + * @throws IOException if there is an error opening the zip + * @throws ZipException if there is an error opening the zip + */ + public ZippedLegacyChunkStore(File zipFile, String folder) throws IOException, ZipException { + this.folder = folder; + + zip = new ZipFile(zipFile); + } + + /** + * Create an instance. The subfolder containing the chunk data will + * be detected. + * + * @param zipFile the zip file + * @throws IOException if there is an error opening the zip + * @throws ZipException if there is an error opening the zip + */ + public ZippedLegacyChunkStore(File zipFile) throws IOException, ZipException { + zip = new ZipFile(zipFile); + } + + /** + * Get the input stream for a chunk file. + * + * @param f1 the first part of the path + * @param f2 the second part of the path + * @param name the name of the file + * @return an input stream + * @throws IOException if there is an error getting the chunk data + * @throws DataException if there is an error getting the chunk data + */ + @Override + protected InputStream getInputStream(String f1, String f2, String name) throws IOException, DataException { + String file = f1 + "/" + f2 + "/" + name; + + // Detect subfolder for the world's files + if (folder != null) { + if (!folder.isEmpty()) { + file = folder + "/" + file; + } + } else { + ZipEntry testEntry = zip.getEntry("level.dat"); + + // So, the data is not in the root directory + if (testEntry == null) { + // Let's try a world/ sub-directory + testEntry = getEntry("world/level.dat"); + + Pattern pattern = Pattern.compile(".*[\\\\/]level\\.dat$"); + + // So not there either... + if (testEntry == null) { + for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { + + testEntry = e.nextElement(); + + // Whoo, found level.dat! + if (pattern.matcher(testEntry.getName()).matches()) { + folder = testEntry.getName().replaceAll("level\\.dat$", ""); + folder = folder.substring(0, folder.length() - 1); + file = folder + file; + break; + } + } + } else { + file = "world/" + file; + } + } + } + + ZipEntry entry = getEntry(file); + if (entry == null) { + throw new MissingChunkException(); + } + try { + return zip.getInputStream(entry); + } catch (ZipException e) { + throw new IOException("Failed to read " + file + " in ZIP"); + } + } + + /** + * Get an entry from the ZIP, trying both types of slashes. + * + * @param file the file + * @return an entry + */ + private ZipEntry getEntry(String file) { + ZipEntry entry = zip.getEntry(file); + if (entry != null) { + return entry; + } + return zip.getEntry(file.replace("/", "\\")); + } + + @Override + public void close() throws IOException { + zip.close(); + } + + @Override + public boolean isValid() { + return true; // Yeah, oh well + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java new file mode 100644 index 0000000..a4ea093 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java @@ -0,0 +1,162 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +/** + * Represents the chunk store used by Minecraft alpha but zipped. + */ +public class ZippedMcRegionChunkStore extends McRegionChunkStore { + + protected File zipFile; + protected ZipFile zip; + protected String folder; + + /** + * Create an instance. The folder argument lets you choose a folder or + * path to look into in the ZIP for the files. Use a blank string for + * the folder to not look into a subdirectory. + * + * @param zipFile the ZIP file + * @param folder the folder + * @throws IOException if there is an error opening the zip + * @throws ZipException if there is an error opening the zip + */ + public ZippedMcRegionChunkStore(File zipFile, String folder) throws IOException, ZipException { + this.zipFile = zipFile; + this.folder = folder; + + zip = new ZipFile(zipFile); + } + + /** + * Create an instance. The sub-folder containing the chunk data will + * be detected. + * + * @param zipFile the ZIP file + * @throws IOException if there is an error opening the zip + * @throws ZipException if there is an error opening the zip + */ + public ZippedMcRegionChunkStore(File zipFile) throws IOException, ZipException { + this.zipFile = zipFile; + + zip = new ZipFile(zipFile); + } + + @Override + protected InputStream getInputStream(String name, String worldName) throws IOException, DataException { + // Detect subfolder for the world's files + if (folder != null) { + if (!folder.isEmpty()) { + name = folder + "/" + name; + } + } else { + Pattern pattern = Pattern.compile(".*\\.mc[ra]$"); + Pattern worldPattern = Pattern.compile(worldName + "[\\\\/].*"); + for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { + ZipEntry testEntry = e.nextElement(); + // Check for world + String entryName = testEntry.getName(); + if (worldPattern.matcher(entryName).matches()) { + if (pattern.matcher(entryName).matches()) { // does entry end in .mca + int endIndex = entryName.lastIndexOf('/'); + if (endIndex < 0) { + endIndex = entryName.lastIndexOf('\\'); + } + folder = entryName.substring(0, endIndex); + if (folder.endsWith("poi") || folder.endsWith("entities")) { + continue; + } + name = folder + "/" + name; + break; + } + + } + } + + // Check if world is found + if (folder == null) { + throw new MissingWorldException("Target world is not present in ZIP.", worldName); + } + } + + ZipEntry entry = getEntry(name); + if (entry == null) { + if (name.endsWith(".mca")) { // try old mcr format + entry = getEntry(name.replace(".mca", ".mcr")); + if (entry == null) { + throw new MissingChunkException(); + } + } else { + throw new MissingChunkException(); + } + } + try { + return zip.getInputStream(entry); + } catch (ZipException e) { + throw new IOException("Failed to read " + name + " in ZIP"); + } + } + + /** + * Get an entry from the ZIP, trying both types of slashes. + * + * @param file the file + * @return a ZIP entry + */ + private ZipEntry getEntry(String file) { + ZipEntry entry = zip.getEntry(file); + if (entry != null) { + return entry; + } + return zip.getEntry(file.replace("/", "\\")); + } + + @Override + public void close() throws IOException { + zip.close(); + } + + @Override + public boolean isValid() { + for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { + + ZipEntry testEntry = e.nextElement(); + + if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { + return true; + } + } + + return false; + } +} diff --git a/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java b/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java new file mode 100644 index 0000000..ea78ee1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java @@ -0,0 +1,64 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.weather; + +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.Registry; + +public class WeatherType implements Keyed { + + public static final Registry REGISTRY = new Registry<>("weather type"); + + private final String id; + + public WeatherType(String id) { + this.id = id; + } + + @Override + public String getId() { + return this.id; + } + + /** + * Gets the name of this weather, or the ID if the name cannot be found. + * + * @return The name, or ID + */ + public String getName() { + return getId(); + } + + @Override + public String toString() { + return getId(); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof WeatherType && this.id.equals(((WeatherType) obj).id); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java b/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java new file mode 100644 index 0000000..ee2a819 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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 . + */ + +package com.sk89q.worldedit.world.weather; + +import javax.annotation.Nullable; + +public final class WeatherTypes { + + public static final WeatherType CLEAR = register("clear"); + public static final WeatherType RAIN = register("rain"); + public static final WeatherType THUNDER_STORM = register("thunder_storm"); + + private WeatherTypes() { + } + + private static WeatherType register(String id) { + return register(new WeatherType(id)); + } + + public static WeatherType register(WeatherType weather) { + return WeatherType.REGISTRY.register(weather.getId(), weather); + } + + @Nullable + public static WeatherType get(final String id) { + return WeatherType.REGISTRY.get(id); + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 0000000..40da83a --- /dev/null +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1,11 @@ +public net.minecraft.server.MinecraftServer f_129726_ # nextTickTime + +# For regen +public net.minecraft.server.MinecraftServer f_129744_ # storageSource +public net.minecraft.server.level.ServerChunkCache f_8332_ # mainThreadProcessor +public net.minecraft.server.level.ServerChunkCache m_8456_(IILnet/minecraft/world/level/chunk/ChunkStatus;Z)Ljava/util/concurrent/CompletableFuture; # getChunkFutureMainThread + +public net.minecraft.world.level.chunk.ChunkBiomeContainer f_62112_ # biomes +public-f net.minecraft.world.level.storage.PrimaryLevelData f_244409_ # worldOptions + +public net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket (Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/entity/BlockEntityType;Lnet/minecraft/nbt/CompoundTag;)V # constructor diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index b0ad9f8..3a6a8a8 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,70 +1,37 @@ -# This is an example mods.toml file. It contains the data relating to the loading mods. -# There are several mandatory fields (#mandatory), and many more that are optional (#optional). -# The overall format is standard TOML format, v0.5.0. -# Note that there are a couple of TOML lists in this file. -# Find more information on toml format here: https://github.com/toml-lang/toml # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml -modLoader="javafml" #mandatory -# A version range to match for said mod loader - for regular FML @Mod it will be the the FML version. This is currently 47. -loaderVersion="${loader_version_range}" #mandatory -# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. -# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. -license="${mod_license}" +modLoader="javafml" +# A version range to match for said mod loader - for regular FML @Mod it will be the minecraft version (without the 1.) +loaderVersion="[24,)" # A URL to refer people to when problems occur with this mod -#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional -# A list of mods - how many allowed here is determined by the individual mod loader -[[mods]] #mandatory -# The modid of the mod -modId="${mod_id}" #mandatory -# The version number of the mod -version="${mod_version}" #mandatory -# A display name for the mod -displayName="${mod_name}" #mandatory -# A URL to query for updates for this mod. See the JSON update specification https://docs.neoforged.net/docs/misc/updatechecker/ -#updateJSONURL="https://change.me.example.invalid/updates.json" #optional +issueTrackerURL="https://discord.gg/enginehub" # A URL for the "homepage" for this mod, displayed in the mod UI -#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional +displayURL="https://enginehub.org/worldedit/" # A file name (in the root of the mod JAR) containing a logo for display -#logoFile="examplemod.png" #optional +logoFile="worldedit-icon.png" # A text field displayed in the mod UI -#credits="" #optional -# A text field displayed in the mod UI -authors="${mod_authors}" #optional -# Display Test controls the display for your mod in the server connection screen -# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod. -# IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod. -# IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component. -# NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value. -# IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself. -#displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional) - -# The description text for the mod (multi line!) (#mandatory) -description='''${mod_description}''' -# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. -[[dependencies.${mod_id}]] #optional - # the modid of the dependency - modId="neoforge" #mandatory - # Does this dependency have to exist - if not, ordering below must be specified - mandatory=true #mandatory - # The version range of the dependency - versionRange="${neo_version_range}" #mandatory - # An ordering relationship for the dependency - BEFORE or AFTER required if the dependency is not mandatory - # BEFORE - This mod is loaded BEFORE the dependency - # AFTER - This mod is loaded AFTER the dependency +authors="EngineHub" +license="GPL" +# A list of mods - how many allowed here is determined by the individual mod loader +[[mods]] +# The modid of the mod +modId="worldedit" +# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it +version="${version}" + # A display name for the mod +displayName="WorldEdit" +# The description text for the mod (multi line!) +description=''' +WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single- and multi-player. +''' +[[dependencies.worldedit]] + modId="minecraft" + mandatory=true + versionRange="[${minecraftVersion},${nextMajorMinecraftVersion})" ordering="NONE" - # Side this dependency is applied on - BOTH, CLIENT, or SERVER side="BOTH" -# Here's another dependency -[[dependencies.${mod_id}]] - modId="minecraft" +[[dependencies.worldedit]] + modId="forge" mandatory=true - # This version range declares a minimum of the current minecraft version up to but not including the next major version - versionRange="${minecraft_version_range}" + versionRange="[${forgeVersion},)" ordering="NONE" side="BOTH" - -# Features are specific properties of the game environment, that you may want to declare you require. This example declares -# that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't -# stop your mod loading on the server for example. -#[features.${mod_id}] -#openGLVersion="[3.2,)" diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/blocks.114.json b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.114.json new file mode 100644 index 0000000..f89dcb9 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.114.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:air","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Sapling","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":false,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"powerSource":false,"lightValue":15,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"powerSource":false,"lightValue":0,"hardness":2.8,"resistance":2.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.989,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":1.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"powerSource":false,"lightValue":1,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"powerSource":false,"lightValue":1,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"powerSource":false,"lightValue":15,"hardness":2,"resistance":2,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"powerSource":false,"lightValue":0,"hardness":4,"resistance":4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":3,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"powerSource":false,"lightValue":15,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"powerSource":true,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"powerSource":true,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"powerSource":false,"lightValue":1,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"powerSource":false,"lightValue":15,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"powerSource":false,"lightValue":15,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"powerSource":false,"lightValue":1,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"powerSource":false,"lightValue":7,"hardness":22.5,"resistance":600,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"powerSource":false,"lightValue":15,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:glass","localizedName":"Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"powerSource":false,"lightValue":15,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass_path","localizedName":"Grass Path","material":{"powerSource":false,"lightValue":0,"hardness":0.65,"resistance":0.65,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":4.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o'Lantern","material":{"powerSource":false,"lightValue":15,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"powerSource":false,"lightValue":15,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lapis_block","localizedName":"Lapis Lazuli Block","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"powerSource":false,"lightValue":15,"hardness":100,"resistance":100,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#ff0000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"powerSource":true,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:lever","localizedName":"Lever","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:loom","localizedName":"Loom","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"powerSource":false,"lightValue":3,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":true,"hasContainer":false}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"powerSource":false,"lightValue":11,"hardness":-1,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"powerSource":true,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"powerSource":false,"lightValue":0,"hardness":50,"resistance":1200,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"powerSource":true,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"powerSource":true,"lightValue":7,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"powerSource":true,"lightValue":7,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":true,"hasContainer":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"powerSource":false,"lightValue":15,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"powerSource":false,"lightValue":6,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.8,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":true,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#ffffff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#ffffff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spawner","localizedName":"Spawner","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#e5e533","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone","localizedName":"Stone","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#ff0000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"powerSource":true,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:water","localizedName":"Water","material":{"powerSource":false,"lightValue":0,"hardness":100,"resistance":100,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#e5e533","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/blocks.115.json b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.115.json new file mode 100644 index 0000000..5da0aff --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.115.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:air","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Sapling","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":false,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"powerSource":false,"lightValue":15,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"powerSource":false,"lightValue":0,"hardness":2.8,"resistance":2.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.989,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":1.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"powerSource":false,"lightValue":1,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"powerSource":false,"lightValue":1,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"powerSource":false,"lightValue":15,"hardness":2,"resistance":2,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"powerSource":false,"lightValue":0,"hardness":4,"resistance":4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":3,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"powerSource":false,"lightValue":15,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"powerSource":true,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"powerSource":true,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"powerSource":false,"lightValue":1,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"powerSource":false,"lightValue":15,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"powerSource":false,"lightValue":15,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"powerSource":false,"lightValue":1,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"powerSource":false,"lightValue":7,"hardness":22.5,"resistance":600,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"powerSource":false,"lightValue":15,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:glass","localizedName":"Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"powerSource":false,"lightValue":15,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass_path","localizedName":"Grass Path","material":{"powerSource":false,"lightValue":0,"hardness":0.65,"resistance":0.65,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":4.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o'Lantern","material":{"powerSource":false,"lightValue":15,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"powerSource":false,"lightValue":15,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lapis_block","localizedName":"Lapis Lazuli Block","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"powerSource":false,"lightValue":15,"hardness":100,"resistance":100,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#ff0000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"powerSource":true,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:lever","localizedName":"Lever","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:loom","localizedName":"Loom","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"powerSource":false,"lightValue":3,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":true,"hasContainer":false}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"powerSource":false,"lightValue":11,"hardness":-1,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"powerSource":true,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"powerSource":false,"lightValue":0,"hardness":50,"resistance":1200,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"powerSource":true,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"powerSource":true,"lightValue":7,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"powerSource":true,"lightValue":7,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":true,"hasContainer":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"powerSource":false,"lightValue":15,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"powerSource":false,"lightValue":6,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.8,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":true,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#ffffff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#ffffff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spawner","localizedName":"Spawner","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#e5e533","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone","localizedName":"Stone","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#ff0000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"powerSource":true,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:water","localizedName":"Water","material":{"powerSource":false,"lightValue":0,"hardness":100,"resistance":100,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#e5e533","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/blocks.116.json b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.116.json new file mode 100644 index 0000000..b15d6c3 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.116.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:air","localizedName":"Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":30,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Shoot","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:basalt","localizedName":"Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blackstone","localizedName":"Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.8,"slipperiness":0.989,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":true,"lightValue":1,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":true,"lightValue":15,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chain","localizedName":"Chain","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":22.5,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":600,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:glass","localizedName":"Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grass_path","localizedName":"Grass Path","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.65,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.65,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o'Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_block","localizedName":"Lapis Lazuli Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100,"hasContainer":false,"lightValue":15,"liquid":true,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lever","localizedName":"Lever","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lodestone","localizedName":"Lodestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:loom","localizedName":"Loom","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":3,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1,"hasContainer":false,"lightValue":11,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":true}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_fungus","localizedName":"Potted Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_roots","localizedName":"Potted Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_fungus","localizedName":"Potted Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_roots","localizedName":"Potted Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.8,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":true,"lightValue":10,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_fire","localizedName":"Soul Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_wall_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spawner","localizedName":"Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:stone","localizedName":"Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:target","localizedName":"Target","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines_plant","localizedName":"Twisting Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_button","localizedName":"Warped Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_door","localizedName":"Warped Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water","localizedName":"Water","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines_plant","localizedName":"Weeping Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/blocks.117.json b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.117.json new file mode 100644 index 0000000..3378b74 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.117.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:air","localizedName":"Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":5,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":30.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea","localizedName":"Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Shoot","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:basalt","localizedName":"Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:big_dripleaf_stem","localizedName":"Big Dripleaf Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle","localizedName":"Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle_cake","localizedName":"Cake with Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blackstone","localizedName":"Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle_cake","localizedName":"Cake with Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.8,"slipperiness":0.989,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":true,"lightValue":1,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle_cake","localizedName":"Cake with Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:calcite","localizedName":"Calcite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":15,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle","localizedName":"Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle_cake","localizedName":"Cake with Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines","localizedName":"Cave Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines_plant","localizedName":"Cave Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chain","localizedName":"Chain","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":4.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:copper_block","localizedName":"Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle_cake","localizedName":"Cake with Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate","localizedName":"Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.65,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.65,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":22.5,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":600.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:glass","localizedName":"Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle_cake","localizedName":"Cake with Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle","localizedName":"Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle_cake","localizedName":"Cake with Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":4,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":15,"liquid":true,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava_cauldron","localizedName":"Lava Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lever","localizedName":"Lever","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light","localizedName":"Light","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":3600000.8,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle_cake","localizedName":"Cake with Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle_cake","localizedName":"Cake with Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle_cake","localizedName":"Cake with Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lodestone","localizedName":"Lodestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:loom","localizedName":"Loom","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle_cake","localizedName":"Cake with Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":3,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":2,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_block","localizedName":"Moss Block","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":11,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":true}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle_cake","localizedName":"Cake with Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle_cake","localizedName":"Cake with Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azalea_bush","localizedName":"Potted Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_fungus","localizedName":"Potted Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_roots","localizedName":"Potted Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_flowering_azalea_bush","localizedName":"Potted Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_fungus","localizedName":"Potted Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_roots","localizedName":"Potted Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow","localizedName":"Powder Snow","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow_cauldron","localizedName":"Powder Snow Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle_cake","localizedName":"Cake with Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle","localizedName":"Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle_cake","localizedName":"Cake with Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.8,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":10,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_fire","localizedName":"Soul Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_wall_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spawner","localizedName":"Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:stone","localizedName":"Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:target","localizedName":"Target","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tuff","localizedName":"Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines_plant","localizedName":"Twisting Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_button","localizedName":"Warped Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_door","localizedName":"Warped Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water","localizedName":"Water","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water_cauldron","localizedName":"Water Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines_plant","localizedName":"Weeping Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle","localizedName":"White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle_cake","localizedName":"Cake with White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle_cake","localizedName":"Cake with Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/blocks.119.json b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.119.json new file mode 100644 index 0000000..688a8c9 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.119.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:air","localizedName":"Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":5,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":30.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea","localizedName":"Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Shoot","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:basalt","localizedName":"Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:big_dripleaf_stem","localizedName":"Big Dripleaf Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle","localizedName":"Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle_cake","localizedName":"Cake with Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blackstone","localizedName":"Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle_cake","localizedName":"Cake with Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.8,"slipperiness":0.989,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":true,"lightValue":1,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle_cake","localizedName":"Cake with Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:calcite","localizedName":"Calcite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":15,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle","localizedName":"Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle_cake","localizedName":"Cake with Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines","localizedName":"Cave Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines_plant","localizedName":"Cave Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chain","localizedName":"Chain","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":4.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:copper_block","localizedName":"Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle_cake","localizedName":"Cake with Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate","localizedName":"Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.65,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.65,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":22.5,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":600.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frogspawn","localizedName":"Frogspawn","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:glass","localizedName":"Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle_cake","localizedName":"Cake with Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle","localizedName":"Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle_cake","localizedName":"Cake with Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":4,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":15,"liquid":true,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava_cauldron","localizedName":"Lava Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lever","localizedName":"Lever","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light","localizedName":"Light","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":3600000.8,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle_cake","localizedName":"Cake with Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle_cake","localizedName":"Cake with Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle_cake","localizedName":"Cake with Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lodestone","localizedName":"Lodestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:loom","localizedName":"Loom","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle_cake","localizedName":"Cake with Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":3,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mangrove_button","localizedName":"Mangrove Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_door","localizedName":"Mangrove Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_fence","localizedName":"Mangrove Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_fence_gate","localizedName":"Mangrove Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_leaves","localizedName":"Mangrove Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_log","localizedName":"Mangrove Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_planks","localizedName":"Mangrove Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_pressure_plate","localizedName":"Mangrove Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_propagule","localizedName":"Mangrove Propagule","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_roots","localizedName":"Mangrove Roots","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_sign","localizedName":"Mangrove Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_slab","localizedName":"Mangrove Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_stairs","localizedName":"Mangrove Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_trapdoor","localizedName":"Mangrove Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wall_sign","localizedName":"Mangrove Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wood","localizedName":"Mangrove Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":2,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_block","localizedName":"Moss Block","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:mud","localizedName":"Mud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mud_brick_slab","localizedName":"Mud Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_brick_stairs","localizedName":"Mud Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_brick_wall","localizedName":"Mud Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_bricks","localizedName":"Mud Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:muddy_mangrove_roots","localizedName":"Muddy Mangrove Roots","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":11,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":true}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ochre_froglight","localizedName":"Ochre Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle_cake","localizedName":"Cake with Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:packed_mud","localizedName":"Packed Mud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pearlescent_froglight","localizedName":"Pearlescent Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle_cake","localizedName":"Cake with Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azalea_bush","localizedName":"Potted Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_fungus","localizedName":"Potted Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_roots","localizedName":"Potted Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_flowering_azalea_bush","localizedName":"Potted Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_mangrove_propagule","localizedName":"Potted Mangrove Propagule","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_fungus","localizedName":"Potted Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_roots","localizedName":"Potted Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow","localizedName":"Powder Snow","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow_cauldron","localizedName":"Powder Snow Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle_cake","localizedName":"Cake with Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle","localizedName":"Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle_cake","localizedName":"Cake with Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:reinforced_deepslate","localizedName":"Reinforced Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":55.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk","localizedName":"Sculk","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_catalyst","localizedName":"Sculk Catalyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_shrieker","localizedName":"Sculk Shrieker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_vein","localizedName":"Sculk Vein","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.8,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":10,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_fire","localizedName":"Soul Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_wall_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spawner","localizedName":"Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:stone","localizedName":"Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_mangrove_log","localizedName":"Stripped Mangrove Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_mangrove_wood","localizedName":"Stripped Mangrove Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:target","localizedName":"Target","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tuff","localizedName":"Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines_plant","localizedName":"Twisting Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:verdant_froglight","localizedName":"Verdant Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_button","localizedName":"Warped Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_door","localizedName":"Warped Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water","localizedName":"Water","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water_cauldron","localizedName":"Water Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines_plant","localizedName":"Weeping Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle","localizedName":"White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle_cake","localizedName":"Cake with White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle_cake","localizedName":"Cake with Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}}] diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/blocks.120.json b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.120.json new file mode 100644 index 0000000..f103eb6 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.120.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_hanging_sign","localizedName":"Acacia Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_hanging_sign","localizedName":"Acacia Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:air","localizedName":"Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":5,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":30.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea","localizedName":"Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_block","localizedName":"Block of Bamboo","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_button","localizedName":"Bamboo Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_door","localizedName":"Bamboo Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_fence","localizedName":"Bamboo Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_fence_gate","localizedName":"Bamboo Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_hanging_sign","localizedName":"Bamboo Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_mosaic","localizedName":"Bamboo Mosaic","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_mosaic_slab","localizedName":"Bamboo Mosaic Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_mosaic_stairs","localizedName":"Bamboo Mosaic Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_planks","localizedName":"Bamboo Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_pressure_plate","localizedName":"Bamboo Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Shoot","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sign","localizedName":"Bamboo Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_slab","localizedName":"Bamboo Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_stairs","localizedName":"Bamboo Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_trapdoor","localizedName":"Bamboo Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_wall_hanging_sign","localizedName":"Bamboo Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_wall_sign","localizedName":"Bamboo Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:basalt","localizedName":"Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:big_dripleaf_stem","localizedName":"Big Dripleaf Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_hanging_sign","localizedName":"Birch Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_hanging_sign","localizedName":"Birch Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle","localizedName":"Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle_cake","localizedName":"Cake with Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#251610","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blackstone","localizedName":"Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle_cake","localizedName":"Cake with Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.8,"slipperiness":0.989,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3e5c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":true,"lightValue":1,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle_cake","localizedName":"Cake with Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#664c33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3223","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:calcite","localizedName":"Calcite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:calibrated_sculk_sensor","localizedName":"Calibrated Sculk Sensor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":15,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle","localizedName":"Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle_cake","localizedName":"Cake with Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines","localizedName":"Cave Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines_plant","localizedName":"Cave Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chain","localizedName":"Chain","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cherry_button","localizedName":"Cherry Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_door","localizedName":"Cherry Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_fence","localizedName":"Cherry Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_fence_gate","localizedName":"Cherry Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_hanging_sign","localizedName":"Cherry Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_leaves","localizedName":"Cherry Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_log","localizedName":"Cherry Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_planks","localizedName":"Cherry Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_pressure_plate","localizedName":"Cherry Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_sapling","localizedName":"Cherry Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_sign","localizedName":"Cherry Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_slab","localizedName":"Cherry Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_stairs","localizedName":"Cherry Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_trapdoor","localizedName":"Cherry Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_wall_hanging_sign","localizedName":"Cherry Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_wall_sign","localizedName":"Cherry Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_wood","localizedName":"Cherry Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:chiseled_bookshelf","localizedName":"Chiseled Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":4.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:copper_block","localizedName":"Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hanging_sign","localizedName":"Crimson Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5c191d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#bd3031","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_hanging_sign","localizedName":"Crimson Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle_cake","localizedName":"Cake with Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#575c5c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_hanging_sign","localizedName":"Dark Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_hanging_sign","localizedName":"Dark Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:decorated_pot","localizedName":"Decorated Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8e3c2e","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:deepslate","localizedName":"Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.65,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.65,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3223","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#00d93a","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":22.5,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":600.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frogspawn","localizedName":"Frogspawn","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:glass","localizedName":"Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fa796","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle_cake","localizedName":"Cake with Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle","localizedName":"Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle_cake","localizedName":"Cake with Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c522a","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_hanging_sign","localizedName":"Jungle Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_hanging_sign","localizedName":"Jungle Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4a80ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":4,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":15,"liquid":true,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava_cauldron","localizedName":"Lava Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lever","localizedName":"Lever","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light","localizedName":"Light","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":3600000.8,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle_cake","localizedName":"Cake with Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#706c8a","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle_cake","localizedName":"Cake with Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle_cake","localizedName":"Cake with Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#677535","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lodestone","localizedName":"Lodestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:loom","localizedName":"Loom","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle_cake","localizedName":"Cake with Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#95576c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":3,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mangrove_button","localizedName":"Mangrove Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_door","localizedName":"Mangrove Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_fence","localizedName":"Mangrove Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_fence_gate","localizedName":"Mangrove Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_hanging_sign","localizedName":"Mangrove Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_leaves","localizedName":"Mangrove Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_log","localizedName":"Mangrove Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_planks","localizedName":"Mangrove Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_pressure_plate","localizedName":"Mangrove Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_propagule","localizedName":"Mangrove Propagule","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_roots","localizedName":"Mangrove Roots","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_sign","localizedName":"Mangrove Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_slab","localizedName":"Mangrove Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_stairs","localizedName":"Mangrove Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_trapdoor","localizedName":"Mangrove Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wall_hanging_sign","localizedName":"Mangrove Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wall_sign","localizedName":"Mangrove Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wood","localizedName":"Mangrove Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":2,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_block","localizedName":"Moss Block","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:mud","localizedName":"Mud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#575c5c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mud_brick_slab","localizedName":"Mud Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_brick_stairs","localizedName":"Mud Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_brick_wall","localizedName":"Mud Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_bricks","localizedName":"Mud Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:muddy_mangrove_roots","localizedName":"Muddy Mangrove Roots","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":11,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":true}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_hanging_sign","localizedName":"Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_hanging_sign","localizedName":"Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ochre_froglight","localizedName":"Ochre Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle_cake","localizedName":"Cake with Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#9f5224","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:packed_mud","localizedName":"Packed Mud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pearlescent_froglight","localizedName":"Pearlescent Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:piglin_head","localizedName":"Piglin Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piglin_wall_head","localizedName":"Piglin Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle_cake","localizedName":"Cake with Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_petals","localizedName":"Pink Petals","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:pitcher_crop","localizedName":"Pitcher Crop","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pitcher_plant","localizedName":"Pitcher Plant","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3223","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azalea_bush","localizedName":"Potted Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cherry_sapling","localizedName":"Potted Cherry Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_fungus","localizedName":"Potted Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_roots","localizedName":"Potted Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_flowering_azalea_bush","localizedName":"Potted Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_mangrove_propagule","localizedName":"Potted Mangrove Propagule","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_torchflower","localizedName":"Potted Torchflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_fungus","localizedName":"Potted Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_roots","localizedName":"Potted Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow","localizedName":"Powder Snow","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow_cauldron","localizedName":"Powder Snow Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle_cake","localizedName":"Cake with Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7a4958","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7a4958","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d8af93","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle","localizedName":"Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle_cake","localizedName":"Cake with Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8e3c2e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:reinforced_deepslate","localizedName":"Reinforced Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":55.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk","localizedName":"Sculk","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_catalyst","localizedName":"Sculk Catalyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_shrieker","localizedName":"Sculk Shrieker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_vein","localizedName":"Sculk Vein","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.8,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sniffer_egg","localizedName":"Sniffer Egg","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":10,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_fire","localizedName":"Soul Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#6699d8","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_wall_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spawner","localizedName":"Monster Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_hanging_sign","localizedName":"Spruce Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_hanging_sign","localizedName":"Spruce Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:stone","localizedName":"Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_bamboo_block","localizedName":"Block of Stripped Bamboo","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_cherry_log","localizedName":"Stripped Cherry Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_cherry_wood","localizedName":"Stripped Cherry Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5c191d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_mangrove_log","localizedName":"Stripped Mangrove Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_mangrove_wood","localizedName":"Stripped Mangrove Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#562c3e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:suspicious_gravel","localizedName":"Suspicious Gravel","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:suspicious_sand","localizedName":"Suspicious Sand","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:target","localizedName":"Target","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torchflower","localizedName":"Torchflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torchflower_crop","localizedName":"Torchflower Crop","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tuff","localizedName":"Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines_plant","localizedName":"Twisting Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:verdant_froglight","localizedName":"Verdant Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#7fa796","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_button","localizedName":"Warped Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_door","localizedName":"Warped Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hanging_sign","localizedName":"Warped Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#562c3e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_hanging_sign","localizedName":"Warped Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#14b485","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water","localizedName":"Water","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water_cauldron","localizedName":"Water Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines_plant","localizedName":"Weeping Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle","localizedName":"White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle_cake","localizedName":"Cake with White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle_cake","localizedName":"Cake with Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ba8524","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json new file mode 100644 index 0000000..bb9137e --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:air","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"powerSource":false,"lightValue":15,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"powerSource":false,"lightValue":0,"hardness":2.8,"resistance":2.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.989,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":1.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"powerSource":false,"lightValue":1,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"powerSource":false,"lightValue":1,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:chest","localizedName":"Chest","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"powerSource":false,"lightValue":0,"hardness":4,"resistance":4,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":3,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"powerSource":false,"lightValue":15,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:creeper_wall_head","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"powerSource":true,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"powerSource":true,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"powerSource":false,"lightValue":1,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:dragon_wall_head","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"powerSource":false,"lightValue":15,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"powerSource":false,"lightValue":15,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"powerSource":false,"lightValue":1,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"powerSource":false,"lightValue":7,"hardness":22.5,"resistance":600,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"powerSource":false,"lightValue":15,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:glass","localizedName":"Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"powerSource":false,"lightValue":15,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass_path","localizedName":"Grass Path","material":{"powerSource":false,"lightValue":0,"hardness":0.65,"resistance":0.65,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":4.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o'Lantern","material":{"powerSource":false,"lightValue":15,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lapis_block","localizedName":"Lapis Lazuli Block","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"powerSource":false,"lightValue":15,"hardness":100,"resistance":100,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#ff0000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lever","localizedName":"Lever","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"powerSource":false,"lightValue":3,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"powerSource":false,"lightValue":11,"hardness":-1,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"powerSource":true,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"powerSource":false,"lightValue":0,"hardness":50,"resistance":1200,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:player_wall_head","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"powerSource":true,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"powerSource":true,"lightValue":7,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Air","material":{"powerSource":true,"lightValue":7,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Dust","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"powerSource":false,"lightValue":15,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"powerSource":false,"lightValue":6,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:sign","localizedName":"Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.8,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":true,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#ffffff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#ffffff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spawner","localizedName":"Spawner","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#e5e533","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone","localizedName":"Stone","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#ff0000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"powerSource":true,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wall_sign","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:wall_torch","localizedName":"Air","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:water","localizedName":"Water","material":{"powerSource":false,"lightValue":0,"hardness":100,"resistance":100,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#e5e533","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:zombie_wall_head","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":true}}] diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/items.114.json b/src/main/resources/com/sk89q/worldedit/world/registry/items.114.json new file mode 100644 index 0000000..690f9fe --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/items.114.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_boat","unlocalizedName":"item.minecraft.acacia_boat","localizedName":"Acacia Boat","maxStackSize":1,"maxDamage":0},{"id":"minecraft:acacia_button","unlocalizedName":"block.minecraft.acacia_button","localizedName":"Acacia Button","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_door","unlocalizedName":"block.minecraft.acacia_door","localizedName":"Acacia Door","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_fence","unlocalizedName":"block.minecraft.acacia_fence","localizedName":"Acacia Fence","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_fence_gate","unlocalizedName":"block.minecraft.acacia_fence_gate","localizedName":"Acacia Fence Gate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_leaves","unlocalizedName":"block.minecraft.acacia_leaves","localizedName":"Acacia Leaves","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_log","unlocalizedName":"block.minecraft.acacia_log","localizedName":"Acacia Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_planks","unlocalizedName":"block.minecraft.acacia_planks","localizedName":"Acacia Planks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_pressure_plate","unlocalizedName":"block.minecraft.acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_sapling","unlocalizedName":"block.minecraft.acacia_sapling","localizedName":"Acacia Sapling","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_sign","unlocalizedName":"block.minecraft.acacia_sign","localizedName":"Acacia Sign","maxStackSize":16,"maxDamage":0},{"id":"minecraft:acacia_slab","unlocalizedName":"block.minecraft.acacia_slab","localizedName":"Acacia Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_stairs","unlocalizedName":"block.minecraft.acacia_stairs","localizedName":"Acacia Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_trapdoor","unlocalizedName":"block.minecraft.acacia_trapdoor","localizedName":"Acacia Trapdoor","maxStackSize":64,"maxDamage":0},{"id":"minecraft:acacia_wood","unlocalizedName":"block.minecraft.acacia_wood","localizedName":"Acacia Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:activator_rail","unlocalizedName":"block.minecraft.activator_rail","localizedName":"Activator Rail","maxStackSize":64,"maxDamage":0},{"id":"minecraft:air","unlocalizedName":"block.minecraft.air","localizedName":"Air","maxStackSize":64,"maxDamage":0},{"id":"minecraft:allium","unlocalizedName":"block.minecraft.allium","localizedName":"Allium","maxStackSize":64,"maxDamage":0},{"id":"minecraft:andesite","unlocalizedName":"block.minecraft.andesite","localizedName":"Andesite","maxStackSize":64,"maxDamage":0},{"id":"minecraft:andesite_slab","unlocalizedName":"block.minecraft.andesite_slab","localizedName":"Andesite Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:andesite_stairs","unlocalizedName":"block.minecraft.andesite_stairs","localizedName":"Andesite Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:andesite_wall","unlocalizedName":"block.minecraft.andesite_wall","localizedName":"Andesite Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:anvil","unlocalizedName":"block.minecraft.anvil","localizedName":"Anvil","maxStackSize":64,"maxDamage":0},{"id":"minecraft:apple","unlocalizedName":"item.minecraft.apple","localizedName":"Apple","maxStackSize":64,"maxDamage":0},{"id":"minecraft:armor_stand","unlocalizedName":"item.minecraft.armor_stand","localizedName":"Armor Stand","maxStackSize":16,"maxDamage":0},{"id":"minecraft:arrow","unlocalizedName":"item.minecraft.arrow","localizedName":"Arrow","maxStackSize":64,"maxDamage":0},{"id":"minecraft:azure_bluet","unlocalizedName":"block.minecraft.azure_bluet","localizedName":"Azure Bluet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:baked_potato","unlocalizedName":"item.minecraft.baked_potato","localizedName":"Baked Potato","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bamboo","unlocalizedName":"block.minecraft.bamboo","localizedName":"Bamboo","maxStackSize":64,"maxDamage":0},{"id":"minecraft:barrel","unlocalizedName":"block.minecraft.barrel","localizedName":"Barrel","maxStackSize":64,"maxDamage":0},{"id":"minecraft:barrier","unlocalizedName":"block.minecraft.barrier","localizedName":"Barrier","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bat_spawn_egg","unlocalizedName":"item.minecraft.bat_spawn_egg","localizedName":"Bat Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:beacon","unlocalizedName":"block.minecraft.beacon","localizedName":"Beacon","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bedrock","unlocalizedName":"block.minecraft.bedrock","localizedName":"Bedrock","maxStackSize":64,"maxDamage":0},{"id":"minecraft:beef","unlocalizedName":"item.minecraft.beef","localizedName":"Raw Beef","maxStackSize":64,"maxDamage":0},{"id":"minecraft:beetroot","unlocalizedName":"item.minecraft.beetroot","localizedName":"Beetroot","maxStackSize":64,"maxDamage":0},{"id":"minecraft:beetroot_seeds","unlocalizedName":"item.minecraft.beetroot_seeds","localizedName":"Beetroot Seeds","maxStackSize":64,"maxDamage":0},{"id":"minecraft:beetroot_soup","unlocalizedName":"item.minecraft.beetroot_soup","localizedName":"Beetroot Soup","maxStackSize":1,"maxDamage":0},{"id":"minecraft:bell","unlocalizedName":"block.minecraft.bell","localizedName":"Bell","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_boat","unlocalizedName":"item.minecraft.birch_boat","localizedName":"Birch Boat","maxStackSize":1,"maxDamage":0},{"id":"minecraft:birch_button","unlocalizedName":"block.minecraft.birch_button","localizedName":"Birch Button","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_door","unlocalizedName":"block.minecraft.birch_door","localizedName":"Birch Door","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_fence","unlocalizedName":"block.minecraft.birch_fence","localizedName":"Birch Fence","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_fence_gate","unlocalizedName":"block.minecraft.birch_fence_gate","localizedName":"Birch Fence Gate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_leaves","unlocalizedName":"block.minecraft.birch_leaves","localizedName":"Birch Leaves","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_log","unlocalizedName":"block.minecraft.birch_log","localizedName":"Birch Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_planks","unlocalizedName":"block.minecraft.birch_planks","localizedName":"Birch Planks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_pressure_plate","unlocalizedName":"block.minecraft.birch_pressure_plate","localizedName":"Birch Pressure Plate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_sapling","unlocalizedName":"block.minecraft.birch_sapling","localizedName":"Birch Sapling","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_sign","unlocalizedName":"block.minecraft.birch_sign","localizedName":"Birch Sign","maxStackSize":16,"maxDamage":0},{"id":"minecraft:birch_slab","unlocalizedName":"block.minecraft.birch_slab","localizedName":"Birch Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_stairs","unlocalizedName":"block.minecraft.birch_stairs","localizedName":"Birch Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_trapdoor","unlocalizedName":"block.minecraft.birch_trapdoor","localizedName":"Birch Trapdoor","maxStackSize":64,"maxDamage":0},{"id":"minecraft:birch_wood","unlocalizedName":"block.minecraft.birch_wood","localizedName":"Birch Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:black_banner","unlocalizedName":"block.minecraft.black_banner","localizedName":"Black Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:black_bed","unlocalizedName":"block.minecraft.black_bed","localizedName":"Black Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:black_carpet","unlocalizedName":"block.minecraft.black_carpet","localizedName":"Black Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:black_concrete","unlocalizedName":"block.minecraft.black_concrete","localizedName":"Black Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:black_concrete_powder","unlocalizedName":"block.minecraft.black_concrete_powder","localizedName":"Black Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:black_dye","unlocalizedName":"item.minecraft.black_dye","localizedName":"Black Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:black_glazed_terracotta","unlocalizedName":"block.minecraft.black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:black_shulker_box","unlocalizedName":"block.minecraft.black_shulker_box","localizedName":"Black Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:black_stained_glass","unlocalizedName":"block.minecraft.black_stained_glass","localizedName":"Black Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:black_stained_glass_pane","unlocalizedName":"block.minecraft.black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:black_terracotta","unlocalizedName":"block.minecraft.black_terracotta","localizedName":"Black Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:black_wool","unlocalizedName":"block.minecraft.black_wool","localizedName":"Black Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blast_furnace","unlocalizedName":"block.minecraft.blast_furnace","localizedName":"Blast Furnace","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blaze_powder","unlocalizedName":"item.minecraft.blaze_powder","localizedName":"Blaze Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blaze_rod","unlocalizedName":"item.minecraft.blaze_rod","localizedName":"Blaze Rod","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blaze_spawn_egg","unlocalizedName":"item.minecraft.blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_banner","unlocalizedName":"block.minecraft.blue_banner","localizedName":"Blue Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:blue_bed","unlocalizedName":"block.minecraft.blue_bed","localizedName":"Blue Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:blue_carpet","unlocalizedName":"block.minecraft.blue_carpet","localizedName":"Blue Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_concrete","unlocalizedName":"block.minecraft.blue_concrete","localizedName":"Blue Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_concrete_powder","unlocalizedName":"block.minecraft.blue_concrete_powder","localizedName":"Blue Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_dye","unlocalizedName":"item.minecraft.blue_dye","localizedName":"Blue Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_glazed_terracotta","unlocalizedName":"block.minecraft.blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_ice","unlocalizedName":"block.minecraft.blue_ice","localizedName":"Blue Ice","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_orchid","unlocalizedName":"block.minecraft.blue_orchid","localizedName":"Blue Orchid","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_shulker_box","unlocalizedName":"block.minecraft.blue_shulker_box","localizedName":"Blue Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:blue_stained_glass","unlocalizedName":"block.minecraft.blue_stained_glass","localizedName":"Blue Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_stained_glass_pane","unlocalizedName":"block.minecraft.blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_terracotta","unlocalizedName":"block.minecraft.blue_terracotta","localizedName":"Blue Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:blue_wool","unlocalizedName":"block.minecraft.blue_wool","localizedName":"Blue Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bone","unlocalizedName":"item.minecraft.bone","localizedName":"Bone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bone_block","unlocalizedName":"block.minecraft.bone_block","localizedName":"Bone Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bone_meal","unlocalizedName":"item.minecraft.bone_meal","localizedName":"Bone Meal","maxStackSize":64,"maxDamage":0},{"id":"minecraft:book","unlocalizedName":"item.minecraft.book","localizedName":"Book","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bookshelf","unlocalizedName":"block.minecraft.bookshelf","localizedName":"Bookshelf","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bow","unlocalizedName":"item.minecraft.bow","localizedName":"Bow","maxStackSize":1,"maxDamage":384},{"id":"minecraft:bowl","unlocalizedName":"item.minecraft.bowl","localizedName":"Bowl","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brain_coral","unlocalizedName":"block.minecraft.brain_coral","localizedName":"Brain Coral","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brain_coral_block","unlocalizedName":"block.minecraft.brain_coral_block","localizedName":"Brain Coral Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brain_coral_fan","unlocalizedName":"block.minecraft.brain_coral_fan","localizedName":"Brain Coral Fan","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bread","unlocalizedName":"item.minecraft.bread","localizedName":"Bread","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brewing_stand","unlocalizedName":"block.minecraft.brewing_stand","localizedName":"Brewing Stand","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brick","unlocalizedName":"item.minecraft.brick","localizedName":"Brick","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brick_slab","unlocalizedName":"block.minecraft.brick_slab","localizedName":"Brick Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brick_stairs","unlocalizedName":"block.minecraft.brick_stairs","localizedName":"Brick Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brick_wall","unlocalizedName":"block.minecraft.brick_wall","localizedName":"Brick Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bricks","unlocalizedName":"block.minecraft.bricks","localizedName":"Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_banner","unlocalizedName":"block.minecraft.brown_banner","localizedName":"Brown Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:brown_bed","unlocalizedName":"block.minecraft.brown_bed","localizedName":"Brown Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:brown_carpet","unlocalizedName":"block.minecraft.brown_carpet","localizedName":"Brown Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_concrete","unlocalizedName":"block.minecraft.brown_concrete","localizedName":"Brown Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_concrete_powder","unlocalizedName":"block.minecraft.brown_concrete_powder","localizedName":"Brown Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_dye","unlocalizedName":"item.minecraft.brown_dye","localizedName":"Brown Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_glazed_terracotta","unlocalizedName":"block.minecraft.brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_mushroom","unlocalizedName":"block.minecraft.brown_mushroom","localizedName":"Brown Mushroom","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_mushroom_block","unlocalizedName":"block.minecraft.brown_mushroom_block","localizedName":"Brown Mushroom Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_shulker_box","unlocalizedName":"block.minecraft.brown_shulker_box","localizedName":"Brown Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:brown_stained_glass","unlocalizedName":"block.minecraft.brown_stained_glass","localizedName":"Brown Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_stained_glass_pane","unlocalizedName":"block.minecraft.brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_terracotta","unlocalizedName":"block.minecraft.brown_terracotta","localizedName":"Brown Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:brown_wool","unlocalizedName":"block.minecraft.brown_wool","localizedName":"Brown Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bubble_coral","unlocalizedName":"block.minecraft.bubble_coral","localizedName":"Bubble Coral","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bubble_coral_block","unlocalizedName":"block.minecraft.bubble_coral_block","localizedName":"Bubble Coral Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bubble_coral_fan","unlocalizedName":"block.minecraft.bubble_coral_fan","localizedName":"Bubble Coral Fan","maxStackSize":64,"maxDamage":0},{"id":"minecraft:bucket","unlocalizedName":"item.minecraft.bucket","localizedName":"Bucket","maxStackSize":16,"maxDamage":0},{"id":"minecraft:cactus","unlocalizedName":"block.minecraft.cactus","localizedName":"Cactus","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cake","unlocalizedName":"block.minecraft.cake","localizedName":"Cake","maxStackSize":1,"maxDamage":0},{"id":"minecraft:campfire","unlocalizedName":"block.minecraft.campfire","localizedName":"Campfire","maxStackSize":64,"maxDamage":0},{"id":"minecraft:carrot","unlocalizedName":"item.minecraft.carrot","localizedName":"Carrot","maxStackSize":64,"maxDamage":0},{"id":"minecraft:carrot_on_a_stick","unlocalizedName":"item.minecraft.carrot_on_a_stick","localizedName":"Carrot on a Stick","maxStackSize":1,"maxDamage":25},{"id":"minecraft:cartography_table","unlocalizedName":"block.minecraft.cartography_table","localizedName":"Cartography Table","maxStackSize":64,"maxDamage":0},{"id":"minecraft:carved_pumpkin","unlocalizedName":"block.minecraft.carved_pumpkin","localizedName":"Carved Pumpkin","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cat_spawn_egg","unlocalizedName":"item.minecraft.cat_spawn_egg","localizedName":"Cat Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cauldron","unlocalizedName":"block.minecraft.cauldron","localizedName":"Cauldron","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cave_spider_spawn_egg","unlocalizedName":"item.minecraft.cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chain_command_block","unlocalizedName":"block.minecraft.chain_command_block","localizedName":"Chain Command Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chainmail_boots","unlocalizedName":"item.minecraft.chainmail_boots","localizedName":"Chainmail Boots","maxStackSize":1,"maxDamage":195},{"id":"minecraft:chainmail_chestplate","unlocalizedName":"item.minecraft.chainmail_chestplate","localizedName":"Chainmail Chestplate","maxStackSize":1,"maxDamage":240},{"id":"minecraft:chainmail_helmet","unlocalizedName":"item.minecraft.chainmail_helmet","localizedName":"Chainmail Helmet","maxStackSize":1,"maxDamage":165},{"id":"minecraft:chainmail_leggings","unlocalizedName":"item.minecraft.chainmail_leggings","localizedName":"Chainmail Leggings","maxStackSize":1,"maxDamage":225},{"id":"minecraft:charcoal","unlocalizedName":"item.minecraft.charcoal","localizedName":"Charcoal","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chest","unlocalizedName":"block.minecraft.chest","localizedName":"Chest","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chest_minecart","unlocalizedName":"item.minecraft.chest_minecart","localizedName":"Minecart with Chest","maxStackSize":1,"maxDamage":0},{"id":"minecraft:chicken","unlocalizedName":"item.minecraft.chicken","localizedName":"Raw Chicken","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chicken_spawn_egg","unlocalizedName":"item.minecraft.chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chipped_anvil","unlocalizedName":"block.minecraft.chipped_anvil","localizedName":"Chipped Anvil","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chiseled_quartz_block","unlocalizedName":"block.minecraft.chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chiseled_red_sandstone","unlocalizedName":"block.minecraft.chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chiseled_sandstone","unlocalizedName":"block.minecraft.chiseled_sandstone","localizedName":"Chiseled Sandstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chiseled_stone_bricks","unlocalizedName":"block.minecraft.chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chorus_flower","unlocalizedName":"block.minecraft.chorus_flower","localizedName":"Chorus Flower","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chorus_fruit","unlocalizedName":"item.minecraft.chorus_fruit","localizedName":"Chorus Fruit","maxStackSize":64,"maxDamage":0},{"id":"minecraft:chorus_plant","unlocalizedName":"block.minecraft.chorus_plant","localizedName":"Chorus Plant","maxStackSize":64,"maxDamage":0},{"id":"minecraft:clay","unlocalizedName":"block.minecraft.clay","localizedName":"Clay","maxStackSize":64,"maxDamage":0},{"id":"minecraft:clay_ball","unlocalizedName":"item.minecraft.clay_ball","localizedName":"Clay","maxStackSize":64,"maxDamage":0},{"id":"minecraft:clock","unlocalizedName":"item.minecraft.clock","localizedName":"Clock","maxStackSize":64,"maxDamage":0},{"id":"minecraft:coal","unlocalizedName":"item.minecraft.coal","localizedName":"Coal","maxStackSize":64,"maxDamage":0},{"id":"minecraft:coal_block","unlocalizedName":"block.minecraft.coal_block","localizedName":"Block of Coal","maxStackSize":64,"maxDamage":0},{"id":"minecraft:coal_ore","unlocalizedName":"block.minecraft.coal_ore","localizedName":"Coal Ore","maxStackSize":64,"maxDamage":0},{"id":"minecraft:coarse_dirt","unlocalizedName":"block.minecraft.coarse_dirt","localizedName":"Coarse Dirt","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cobblestone","unlocalizedName":"block.minecraft.cobblestone","localizedName":"Cobblestone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cobblestone_slab","unlocalizedName":"block.minecraft.cobblestone_slab","localizedName":"Cobblestone Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cobblestone_stairs","unlocalizedName":"block.minecraft.cobblestone_stairs","localizedName":"Cobblestone Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cobblestone_wall","unlocalizedName":"block.minecraft.cobblestone_wall","localizedName":"Cobblestone Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cobweb","unlocalizedName":"block.minecraft.cobweb","localizedName":"Cobweb","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cocoa_beans","unlocalizedName":"item.minecraft.cocoa_beans","localizedName":"Cocoa Beans","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cod","unlocalizedName":"item.minecraft.cod","localizedName":"Raw Cod","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cod_bucket","unlocalizedName":"item.minecraft.cod_bucket","localizedName":"Bucket of Cod","maxStackSize":1,"maxDamage":0},{"id":"minecraft:cod_spawn_egg","unlocalizedName":"item.minecraft.cod_spawn_egg","localizedName":"Cod Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:command_block","unlocalizedName":"block.minecraft.command_block","localizedName":"Command Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:command_block_minecart","unlocalizedName":"item.minecraft.command_block_minecart","localizedName":"Minecart with Command Block","maxStackSize":1,"maxDamage":0},{"id":"minecraft:comparator","unlocalizedName":"block.minecraft.comparator","localizedName":"Redstone Comparator","maxStackSize":64,"maxDamage":0},{"id":"minecraft:compass","unlocalizedName":"item.minecraft.compass","localizedName":"Compass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:composter","unlocalizedName":"block.minecraft.composter","localizedName":"Composter","maxStackSize":64,"maxDamage":0},{"id":"minecraft:conduit","unlocalizedName":"block.minecraft.conduit","localizedName":"Conduit","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cooked_beef","unlocalizedName":"item.minecraft.cooked_beef","localizedName":"Steak","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cooked_chicken","unlocalizedName":"item.minecraft.cooked_chicken","localizedName":"Cooked Chicken","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cooked_cod","unlocalizedName":"item.minecraft.cooked_cod","localizedName":"Cooked Cod","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cooked_mutton","unlocalizedName":"item.minecraft.cooked_mutton","localizedName":"Cooked Mutton","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cooked_porkchop","unlocalizedName":"item.minecraft.cooked_porkchop","localizedName":"Cooked Porkchop","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cooked_rabbit","unlocalizedName":"item.minecraft.cooked_rabbit","localizedName":"Cooked Rabbit","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cooked_salmon","unlocalizedName":"item.minecraft.cooked_salmon","localizedName":"Cooked Salmon","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cookie","unlocalizedName":"item.minecraft.cookie","localizedName":"Cookie","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cornflower","unlocalizedName":"block.minecraft.cornflower","localizedName":"Cornflower","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cow_spawn_egg","unlocalizedName":"item.minecraft.cow_spawn_egg","localizedName":"Cow Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cracked_stone_bricks","unlocalizedName":"block.minecraft.cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:crafting_table","unlocalizedName":"block.minecraft.crafting_table","localizedName":"Crafting Table","maxStackSize":64,"maxDamage":0},{"id":"minecraft:creeper_banner_pattern","unlocalizedName":"item.minecraft.creeper_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"maxDamage":0},{"id":"minecraft:creeper_head","unlocalizedName":"block.minecraft.creeper_head","localizedName":"Creeper Head","maxStackSize":64,"maxDamage":0},{"id":"minecraft:creeper_spawn_egg","unlocalizedName":"item.minecraft.creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:crossbow","unlocalizedName":"item.minecraft.crossbow","localizedName":"Crossbow","maxStackSize":1,"maxDamage":326},{"id":"minecraft:cut_red_sandstone","unlocalizedName":"block.minecraft.cut_red_sandstone","localizedName":"Cut Red Sandstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cut_red_sandstone_slab","unlocalizedName":"block.minecraft.cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cut_sandstone","unlocalizedName":"block.minecraft.cut_sandstone","localizedName":"Cut Sandstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cut_sandstone_slab","unlocalizedName":"block.minecraft.cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cyan_banner","unlocalizedName":"block.minecraft.cyan_banner","localizedName":"Cyan Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:cyan_bed","unlocalizedName":"block.minecraft.cyan_bed","localizedName":"Cyan Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:cyan_carpet","unlocalizedName":"block.minecraft.cyan_carpet","localizedName":"Cyan Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cyan_concrete","unlocalizedName":"block.minecraft.cyan_concrete","localizedName":"Cyan Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cyan_concrete_powder","unlocalizedName":"block.minecraft.cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cyan_dye","unlocalizedName":"item.minecraft.cyan_dye","localizedName":"Cyan Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cyan_glazed_terracotta","unlocalizedName":"block.minecraft.cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cyan_shulker_box","unlocalizedName":"block.minecraft.cyan_shulker_box","localizedName":"Cyan Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:cyan_stained_glass","unlocalizedName":"block.minecraft.cyan_stained_glass","localizedName":"Cyan Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cyan_stained_glass_pane","unlocalizedName":"block.minecraft.cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cyan_terracotta","unlocalizedName":"block.minecraft.cyan_terracotta","localizedName":"Cyan Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:cyan_wool","unlocalizedName":"block.minecraft.cyan_wool","localizedName":"Cyan Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:damaged_anvil","unlocalizedName":"block.minecraft.damaged_anvil","localizedName":"Damaged Anvil","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dandelion","unlocalizedName":"block.minecraft.dandelion","localizedName":"Dandelion","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_boat","unlocalizedName":"item.minecraft.dark_oak_boat","localizedName":"Dark Oak Boat","maxStackSize":1,"maxDamage":0},{"id":"minecraft:dark_oak_button","unlocalizedName":"block.minecraft.dark_oak_button","localizedName":"Dark Oak Button","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_door","unlocalizedName":"block.minecraft.dark_oak_door","localizedName":"Dark Oak Door","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_fence","unlocalizedName":"block.minecraft.dark_oak_fence","localizedName":"Dark Oak Fence","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_fence_gate","unlocalizedName":"block.minecraft.dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_leaves","unlocalizedName":"block.minecraft.dark_oak_leaves","localizedName":"Dark Oak Leaves","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_log","unlocalizedName":"block.minecraft.dark_oak_log","localizedName":"Dark Oak Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_planks","unlocalizedName":"block.minecraft.dark_oak_planks","localizedName":"Dark Oak Planks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_pressure_plate","unlocalizedName":"block.minecraft.dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_sapling","unlocalizedName":"block.minecraft.dark_oak_sapling","localizedName":"Dark Oak Sapling","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_sign","unlocalizedName":"block.minecraft.dark_oak_sign","localizedName":"Dark Oak Sign","maxStackSize":16,"maxDamage":0},{"id":"minecraft:dark_oak_slab","unlocalizedName":"block.minecraft.dark_oak_slab","localizedName":"Dark Oak Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_stairs","unlocalizedName":"block.minecraft.dark_oak_stairs","localizedName":"Dark Oak Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_trapdoor","unlocalizedName":"block.minecraft.dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_oak_wood","unlocalizedName":"block.minecraft.dark_oak_wood","localizedName":"Dark Oak Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_prismarine","unlocalizedName":"block.minecraft.dark_prismarine","localizedName":"Dark Prismarine","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_prismarine_slab","unlocalizedName":"block.minecraft.dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dark_prismarine_stairs","unlocalizedName":"block.minecraft.dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:daylight_detector","unlocalizedName":"block.minecraft.daylight_detector","localizedName":"Daylight Detector","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_brain_coral","unlocalizedName":"block.minecraft.dead_brain_coral","localizedName":"Dead Brain Coral","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_brain_coral_block","unlocalizedName":"block.minecraft.dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_brain_coral_fan","unlocalizedName":"block.minecraft.dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_bubble_coral","unlocalizedName":"block.minecraft.dead_bubble_coral","localizedName":"Dead Bubble Coral","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_bubble_coral_block","unlocalizedName":"block.minecraft.dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_bubble_coral_fan","unlocalizedName":"block.minecraft.dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_bush","unlocalizedName":"block.minecraft.dead_bush","localizedName":"Dead Bush","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_fire_coral","unlocalizedName":"block.minecraft.dead_fire_coral","localizedName":"Dead Fire Coral","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_fire_coral_block","unlocalizedName":"block.minecraft.dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_fire_coral_fan","unlocalizedName":"block.minecraft.dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_horn_coral","unlocalizedName":"block.minecraft.dead_horn_coral","localizedName":"Dead Horn Coral","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_horn_coral_block","unlocalizedName":"block.minecraft.dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_horn_coral_fan","unlocalizedName":"block.minecraft.dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_tube_coral","unlocalizedName":"block.minecraft.dead_tube_coral","localizedName":"Dead Tube Coral","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_tube_coral_block","unlocalizedName":"block.minecraft.dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dead_tube_coral_fan","unlocalizedName":"block.minecraft.dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxStackSize":64,"maxDamage":0},{"id":"minecraft:debug_stick","unlocalizedName":"item.minecraft.debug_stick","localizedName":"Debug Stick","maxStackSize":1,"maxDamage":0},{"id":"minecraft:detector_rail","unlocalizedName":"block.minecraft.detector_rail","localizedName":"Detector Rail","maxStackSize":64,"maxDamage":0},{"id":"minecraft:diamond","unlocalizedName":"item.minecraft.diamond","localizedName":"Diamond","maxStackSize":64,"maxDamage":0},{"id":"minecraft:diamond_axe","unlocalizedName":"item.minecraft.diamond_axe","localizedName":"Diamond Axe","maxStackSize":1,"maxDamage":1561},{"id":"minecraft:diamond_block","unlocalizedName":"block.minecraft.diamond_block","localizedName":"Block of Diamond","maxStackSize":64,"maxDamage":0},{"id":"minecraft:diamond_boots","unlocalizedName":"item.minecraft.diamond_boots","localizedName":"Diamond Boots","maxStackSize":1,"maxDamage":429},{"id":"minecraft:diamond_chestplate","unlocalizedName":"item.minecraft.diamond_chestplate","localizedName":"Diamond Chestplate","maxStackSize":1,"maxDamage":528},{"id":"minecraft:diamond_helmet","unlocalizedName":"item.minecraft.diamond_helmet","localizedName":"Diamond Helmet","maxStackSize":1,"maxDamage":363},{"id":"minecraft:diamond_hoe","unlocalizedName":"item.minecraft.diamond_hoe","localizedName":"Diamond Hoe","maxStackSize":1,"maxDamage":1561},{"id":"minecraft:diamond_horse_armor","unlocalizedName":"item.minecraft.diamond_horse_armor","localizedName":"Diamond Horse Armor","maxStackSize":1,"maxDamage":0},{"id":"minecraft:diamond_leggings","unlocalizedName":"item.minecraft.diamond_leggings","localizedName":"Diamond Leggings","maxStackSize":1,"maxDamage":495},{"id":"minecraft:diamond_ore","unlocalizedName":"block.minecraft.diamond_ore","localizedName":"Diamond Ore","maxStackSize":64,"maxDamage":0},{"id":"minecraft:diamond_pickaxe","unlocalizedName":"item.minecraft.diamond_pickaxe","localizedName":"Diamond Pickaxe","maxStackSize":1,"maxDamage":1561},{"id":"minecraft:diamond_shovel","unlocalizedName":"item.minecraft.diamond_shovel","localizedName":"Diamond Shovel","maxStackSize":1,"maxDamage":1561},{"id":"minecraft:diamond_sword","unlocalizedName":"item.minecraft.diamond_sword","localizedName":"Diamond Sword","maxStackSize":1,"maxDamage":1561},{"id":"minecraft:diorite","unlocalizedName":"block.minecraft.diorite","localizedName":"Diorite","maxStackSize":64,"maxDamage":0},{"id":"minecraft:diorite_slab","unlocalizedName":"block.minecraft.diorite_slab","localizedName":"Diorite Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:diorite_stairs","unlocalizedName":"block.minecraft.diorite_stairs","localizedName":"Diorite Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:diorite_wall","unlocalizedName":"block.minecraft.diorite_wall","localizedName":"Diorite Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dirt","unlocalizedName":"block.minecraft.dirt","localizedName":"Dirt","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dispenser","unlocalizedName":"block.minecraft.dispenser","localizedName":"Dispenser","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dolphin_spawn_egg","unlocalizedName":"item.minecraft.dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:donkey_spawn_egg","unlocalizedName":"item.minecraft.donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dragon_breath","unlocalizedName":"item.minecraft.dragon_breath","localizedName":"Dragon's Breath","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dragon_egg","unlocalizedName":"block.minecraft.dragon_egg","localizedName":"Dragon Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dragon_head","unlocalizedName":"block.minecraft.dragon_head","localizedName":"Dragon Head","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dried_kelp","unlocalizedName":"item.minecraft.dried_kelp","localizedName":"Dried Kelp","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dried_kelp_block","unlocalizedName":"block.minecraft.dried_kelp_block","localizedName":"Dried Kelp Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:dropper","unlocalizedName":"block.minecraft.dropper","localizedName":"Dropper","maxStackSize":64,"maxDamage":0},{"id":"minecraft:drowned_spawn_egg","unlocalizedName":"item.minecraft.drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:egg","unlocalizedName":"item.minecraft.egg","localizedName":"Egg","maxStackSize":16,"maxDamage":0},{"id":"minecraft:elder_guardian_spawn_egg","unlocalizedName":"item.minecraft.elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:elytra","unlocalizedName":"item.minecraft.elytra","localizedName":"Elytra","maxStackSize":1,"maxDamage":432},{"id":"minecraft:emerald","unlocalizedName":"item.minecraft.emerald","localizedName":"Emerald","maxStackSize":64,"maxDamage":0},{"id":"minecraft:emerald_block","unlocalizedName":"block.minecraft.emerald_block","localizedName":"Block of Emerald","maxStackSize":64,"maxDamage":0},{"id":"minecraft:emerald_ore","unlocalizedName":"block.minecraft.emerald_ore","localizedName":"Emerald Ore","maxStackSize":64,"maxDamage":0},{"id":"minecraft:enchanted_book","unlocalizedName":"item.minecraft.enchanted_book","localizedName":"Enchanted Book","maxStackSize":1,"maxDamage":0},{"id":"minecraft:enchanted_golden_apple","unlocalizedName":"item.minecraft.enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxStackSize":64,"maxDamage":0},{"id":"minecraft:enchanting_table","unlocalizedName":"block.minecraft.enchanting_table","localizedName":"Enchanting Table","maxStackSize":64,"maxDamage":0},{"id":"minecraft:end_crystal","unlocalizedName":"item.minecraft.end_crystal","localizedName":"End Crystal","maxStackSize":64,"maxDamage":0},{"id":"minecraft:end_portal_frame","unlocalizedName":"block.minecraft.end_portal_frame","localizedName":"End Portal Frame","maxStackSize":64,"maxDamage":0},{"id":"minecraft:end_rod","unlocalizedName":"block.minecraft.end_rod","localizedName":"End Rod","maxStackSize":64,"maxDamage":0},{"id":"minecraft:end_stone","unlocalizedName":"block.minecraft.end_stone","localizedName":"End Stone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:end_stone_brick_slab","unlocalizedName":"block.minecraft.end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:end_stone_brick_stairs","unlocalizedName":"block.minecraft.end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:end_stone_brick_wall","unlocalizedName":"block.minecraft.end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:end_stone_bricks","unlocalizedName":"block.minecraft.end_stone_bricks","localizedName":"End Stone Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:ender_chest","unlocalizedName":"block.minecraft.ender_chest","localizedName":"Ender Chest","maxStackSize":64,"maxDamage":0},{"id":"minecraft:ender_eye","unlocalizedName":"item.minecraft.ender_eye","localizedName":"Eye of Ender","maxStackSize":64,"maxDamage":0},{"id":"minecraft:ender_pearl","unlocalizedName":"item.minecraft.ender_pearl","localizedName":"Ender Pearl","maxStackSize":16,"maxDamage":0},{"id":"minecraft:enderman_spawn_egg","unlocalizedName":"item.minecraft.enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:endermite_spawn_egg","unlocalizedName":"item.minecraft.endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:evoker_spawn_egg","unlocalizedName":"item.minecraft.evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:experience_bottle","unlocalizedName":"item.minecraft.experience_bottle","localizedName":"Bottle o' Enchanting","maxStackSize":64,"maxDamage":0},{"id":"minecraft:farmland","unlocalizedName":"block.minecraft.farmland","localizedName":"Farmland","maxStackSize":64,"maxDamage":0},{"id":"minecraft:feather","unlocalizedName":"item.minecraft.feather","localizedName":"Feather","maxStackSize":64,"maxDamage":0},{"id":"minecraft:fermented_spider_eye","unlocalizedName":"item.minecraft.fermented_spider_eye","localizedName":"Fermented Spider Eye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:fern","unlocalizedName":"block.minecraft.fern","localizedName":"Fern","maxStackSize":64,"maxDamage":0},{"id":"minecraft:filled_map","unlocalizedName":"item.minecraft.filled_map","localizedName":"Map","maxStackSize":64,"maxDamage":0},{"id":"minecraft:fire_charge","unlocalizedName":"item.minecraft.fire_charge","localizedName":"Fire Charge","maxStackSize":64,"maxDamage":0},{"id":"minecraft:fire_coral","unlocalizedName":"block.minecraft.fire_coral","localizedName":"Fire Coral","maxStackSize":64,"maxDamage":0},{"id":"minecraft:fire_coral_block","unlocalizedName":"block.minecraft.fire_coral_block","localizedName":"Fire Coral Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:fire_coral_fan","unlocalizedName":"block.minecraft.fire_coral_fan","localizedName":"Fire Coral Fan","maxStackSize":64,"maxDamage":0},{"id":"minecraft:firework_rocket","unlocalizedName":"item.minecraft.firework_rocket","localizedName":"Firework Rocket","maxStackSize":64,"maxDamage":0},{"id":"minecraft:firework_star","unlocalizedName":"item.minecraft.firework_star","localizedName":"Firework Star","maxStackSize":64,"maxDamage":0},{"id":"minecraft:fishing_rod","unlocalizedName":"item.minecraft.fishing_rod","localizedName":"Fishing Rod","maxStackSize":1,"maxDamage":64},{"id":"minecraft:fletching_table","unlocalizedName":"block.minecraft.fletching_table","localizedName":"Fletching Table","maxStackSize":64,"maxDamage":0},{"id":"minecraft:flint","unlocalizedName":"item.minecraft.flint","localizedName":"Flint","maxStackSize":64,"maxDamage":0},{"id":"minecraft:flint_and_steel","unlocalizedName":"item.minecraft.flint_and_steel","localizedName":"Flint and Steel","maxStackSize":1,"maxDamage":64},{"id":"minecraft:flower_banner_pattern","unlocalizedName":"item.minecraft.flower_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"maxDamage":0},{"id":"minecraft:flower_pot","unlocalizedName":"block.minecraft.flower_pot","localizedName":"Flower Pot","maxStackSize":64,"maxDamage":0},{"id":"minecraft:fox_spawn_egg","unlocalizedName":"item.minecraft.fox_spawn_egg","localizedName":"Fox Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:furnace","unlocalizedName":"block.minecraft.furnace","localizedName":"Furnace","maxStackSize":64,"maxDamage":0},{"id":"minecraft:furnace_minecart","unlocalizedName":"item.minecraft.furnace_minecart","localizedName":"Minecart with Furnace","maxStackSize":1,"maxDamage":0},{"id":"minecraft:ghast_spawn_egg","unlocalizedName":"item.minecraft.ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:ghast_tear","unlocalizedName":"item.minecraft.ghast_tear","localizedName":"Ghast Tear","maxStackSize":64,"maxDamage":0},{"id":"minecraft:glass","unlocalizedName":"block.minecraft.glass","localizedName":"Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:glass_bottle","unlocalizedName":"item.minecraft.glass_bottle","localizedName":"Glass Bottle","maxStackSize":64,"maxDamage":0},{"id":"minecraft:glass_pane","unlocalizedName":"block.minecraft.glass_pane","localizedName":"Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:glistering_melon_slice","unlocalizedName":"item.minecraft.glistering_melon_slice","localizedName":"Glistering Melon Slice","maxStackSize":64,"maxDamage":0},{"id":"minecraft:globe_banner_pattern","unlocalizedName":"item.minecraft.globe_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"maxDamage":0},{"id":"minecraft:glowstone","unlocalizedName":"block.minecraft.glowstone","localizedName":"Glowstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:glowstone_dust","unlocalizedName":"item.minecraft.glowstone_dust","localizedName":"Glowstone Dust","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gold_block","unlocalizedName":"block.minecraft.gold_block","localizedName":"Block of Gold","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gold_ingot","unlocalizedName":"item.minecraft.gold_ingot","localizedName":"Gold Ingot","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gold_nugget","unlocalizedName":"item.minecraft.gold_nugget","localizedName":"Gold Nugget","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gold_ore","unlocalizedName":"block.minecraft.gold_ore","localizedName":"Gold Ore","maxStackSize":64,"maxDamage":0},{"id":"minecraft:golden_apple","unlocalizedName":"item.minecraft.golden_apple","localizedName":"Golden Apple","maxStackSize":64,"maxDamage":0},{"id":"minecraft:golden_axe","unlocalizedName":"item.minecraft.golden_axe","localizedName":"Golden Axe","maxStackSize":1,"maxDamage":32},{"id":"minecraft:golden_boots","unlocalizedName":"item.minecraft.golden_boots","localizedName":"Golden Boots","maxStackSize":1,"maxDamage":91},{"id":"minecraft:golden_carrot","unlocalizedName":"item.minecraft.golden_carrot","localizedName":"Golden Carrot","maxStackSize":64,"maxDamage":0},{"id":"minecraft:golden_chestplate","unlocalizedName":"item.minecraft.golden_chestplate","localizedName":"Golden Chestplate","maxStackSize":1,"maxDamage":112},{"id":"minecraft:golden_helmet","unlocalizedName":"item.minecraft.golden_helmet","localizedName":"Golden Helmet","maxStackSize":1,"maxDamage":77},{"id":"minecraft:golden_hoe","unlocalizedName":"item.minecraft.golden_hoe","localizedName":"Golden Hoe","maxStackSize":1,"maxDamage":32},{"id":"minecraft:golden_horse_armor","unlocalizedName":"item.minecraft.golden_horse_armor","localizedName":"Golden Horse Armor","maxStackSize":1,"maxDamage":0},{"id":"minecraft:golden_leggings","unlocalizedName":"item.minecraft.golden_leggings","localizedName":"Golden Leggings","maxStackSize":1,"maxDamage":105},{"id":"minecraft:golden_pickaxe","unlocalizedName":"item.minecraft.golden_pickaxe","localizedName":"Golden Pickaxe","maxStackSize":1,"maxDamage":32},{"id":"minecraft:golden_shovel","unlocalizedName":"item.minecraft.golden_shovel","localizedName":"Golden Shovel","maxStackSize":1,"maxDamage":32},{"id":"minecraft:golden_sword","unlocalizedName":"item.minecraft.golden_sword","localizedName":"Golden Sword","maxStackSize":1,"maxDamage":32},{"id":"minecraft:granite","unlocalizedName":"block.minecraft.granite","localizedName":"Granite","maxStackSize":64,"maxDamage":0},{"id":"minecraft:granite_slab","unlocalizedName":"block.minecraft.granite_slab","localizedName":"Granite Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:granite_stairs","unlocalizedName":"block.minecraft.granite_stairs","localizedName":"Granite Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:granite_wall","unlocalizedName":"block.minecraft.granite_wall","localizedName":"Granite Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:grass","unlocalizedName":"block.minecraft.grass","localizedName":"Grass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:grass_block","unlocalizedName":"block.minecraft.grass_block","localizedName":"Grass Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:grass_path","unlocalizedName":"block.minecraft.grass_path","localizedName":"Grass Path","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gravel","unlocalizedName":"block.minecraft.gravel","localizedName":"Gravel","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gray_banner","unlocalizedName":"block.minecraft.gray_banner","localizedName":"Gray Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:gray_bed","unlocalizedName":"block.minecraft.gray_bed","localizedName":"Gray Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:gray_carpet","unlocalizedName":"block.minecraft.gray_carpet","localizedName":"Gray Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gray_concrete","unlocalizedName":"block.minecraft.gray_concrete","localizedName":"Gray Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gray_concrete_powder","unlocalizedName":"block.minecraft.gray_concrete_powder","localizedName":"Gray Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gray_dye","unlocalizedName":"item.minecraft.gray_dye","localizedName":"Gray Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gray_glazed_terracotta","unlocalizedName":"block.minecraft.gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gray_shulker_box","unlocalizedName":"block.minecraft.gray_shulker_box","localizedName":"Gray Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:gray_stained_glass","unlocalizedName":"block.minecraft.gray_stained_glass","localizedName":"Gray Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gray_stained_glass_pane","unlocalizedName":"block.minecraft.gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gray_terracotta","unlocalizedName":"block.minecraft.gray_terracotta","localizedName":"Gray Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gray_wool","unlocalizedName":"block.minecraft.gray_wool","localizedName":"Gray Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:green_banner","unlocalizedName":"block.minecraft.green_banner","localizedName":"Green Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:green_bed","unlocalizedName":"block.minecraft.green_bed","localizedName":"Green Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:green_carpet","unlocalizedName":"block.minecraft.green_carpet","localizedName":"Green Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:green_concrete","unlocalizedName":"block.minecraft.green_concrete","localizedName":"Green Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:green_concrete_powder","unlocalizedName":"block.minecraft.green_concrete_powder","localizedName":"Green Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:green_dye","unlocalizedName":"item.minecraft.green_dye","localizedName":"Green Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:green_glazed_terracotta","unlocalizedName":"block.minecraft.green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:green_shulker_box","unlocalizedName":"block.minecraft.green_shulker_box","localizedName":"Green Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:green_stained_glass","unlocalizedName":"block.minecraft.green_stained_glass","localizedName":"Green Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:green_stained_glass_pane","unlocalizedName":"block.minecraft.green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:green_terracotta","unlocalizedName":"block.minecraft.green_terracotta","localizedName":"Green Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:green_wool","unlocalizedName":"block.minecraft.green_wool","localizedName":"Green Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:grindstone","unlocalizedName":"block.minecraft.grindstone","localizedName":"Grindstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:guardian_spawn_egg","unlocalizedName":"item.minecraft.guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:gunpowder","unlocalizedName":"item.minecraft.gunpowder","localizedName":"Gunpowder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:hay_block","unlocalizedName":"block.minecraft.hay_block","localizedName":"Hay Bale","maxStackSize":64,"maxDamage":0},{"id":"minecraft:heart_of_the_sea","unlocalizedName":"item.minecraft.heart_of_the_sea","localizedName":"Heart of the Sea","maxStackSize":64,"maxDamage":0},{"id":"minecraft:heavy_weighted_pressure_plate","unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:hopper","unlocalizedName":"block.minecraft.hopper","localizedName":"Hopper","maxStackSize":64,"maxDamage":0},{"id":"minecraft:hopper_minecart","unlocalizedName":"item.minecraft.hopper_minecart","localizedName":"Minecart with Hopper","maxStackSize":1,"maxDamage":0},{"id":"minecraft:horn_coral","unlocalizedName":"block.minecraft.horn_coral","localizedName":"Horn Coral","maxStackSize":64,"maxDamage":0},{"id":"minecraft:horn_coral_block","unlocalizedName":"block.minecraft.horn_coral_block","localizedName":"Horn Coral Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:horn_coral_fan","unlocalizedName":"block.minecraft.horn_coral_fan","localizedName":"Horn Coral Fan","maxStackSize":64,"maxDamage":0},{"id":"minecraft:horse_spawn_egg","unlocalizedName":"item.minecraft.horse_spawn_egg","localizedName":"Horse Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:husk_spawn_egg","unlocalizedName":"item.minecraft.husk_spawn_egg","localizedName":"Husk Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:ice","unlocalizedName":"block.minecraft.ice","localizedName":"Ice","maxStackSize":64,"maxDamage":0},{"id":"minecraft:infested_chiseled_stone_bricks","unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:infested_cobblestone","unlocalizedName":"block.minecraft.infested_cobblestone","localizedName":"Infested Cobblestone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:infested_cracked_stone_bricks","unlocalizedName":"block.minecraft.infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:infested_mossy_stone_bricks","unlocalizedName":"block.minecraft.infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:infested_stone","unlocalizedName":"block.minecraft.infested_stone","localizedName":"Infested Stone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:infested_stone_bricks","unlocalizedName":"block.minecraft.infested_stone_bricks","localizedName":"Infested Stone Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:ink_sac","unlocalizedName":"item.minecraft.ink_sac","localizedName":"Ink Sac","maxStackSize":64,"maxDamage":0},{"id":"minecraft:iron_axe","unlocalizedName":"item.minecraft.iron_axe","localizedName":"Iron Axe","maxStackSize":1,"maxDamage":250},{"id":"minecraft:iron_bars","unlocalizedName":"block.minecraft.iron_bars","localizedName":"Iron Bars","maxStackSize":64,"maxDamage":0},{"id":"minecraft:iron_block","unlocalizedName":"block.minecraft.iron_block","localizedName":"Block of Iron","maxStackSize":64,"maxDamage":0},{"id":"minecraft:iron_boots","unlocalizedName":"item.minecraft.iron_boots","localizedName":"Iron Boots","maxStackSize":1,"maxDamage":195},{"id":"minecraft:iron_chestplate","unlocalizedName":"item.minecraft.iron_chestplate","localizedName":"Iron Chestplate","maxStackSize":1,"maxDamage":240},{"id":"minecraft:iron_door","unlocalizedName":"block.minecraft.iron_door","localizedName":"Iron Door","maxStackSize":64,"maxDamage":0},{"id":"minecraft:iron_helmet","unlocalizedName":"item.minecraft.iron_helmet","localizedName":"Iron Helmet","maxStackSize":1,"maxDamage":165},{"id":"minecraft:iron_hoe","unlocalizedName":"item.minecraft.iron_hoe","localizedName":"Iron Hoe","maxStackSize":1,"maxDamage":250},{"id":"minecraft:iron_horse_armor","unlocalizedName":"item.minecraft.iron_horse_armor","localizedName":"Iron Horse Armor","maxStackSize":1,"maxDamage":0},{"id":"minecraft:iron_ingot","unlocalizedName":"item.minecraft.iron_ingot","localizedName":"Iron Ingot","maxStackSize":64,"maxDamage":0},{"id":"minecraft:iron_leggings","unlocalizedName":"item.minecraft.iron_leggings","localizedName":"Iron Leggings","maxStackSize":1,"maxDamage":225},{"id":"minecraft:iron_nugget","unlocalizedName":"item.minecraft.iron_nugget","localizedName":"Iron Nugget","maxStackSize":64,"maxDamage":0},{"id":"minecraft:iron_ore","unlocalizedName":"block.minecraft.iron_ore","localizedName":"Iron Ore","maxStackSize":64,"maxDamage":0},{"id":"minecraft:iron_pickaxe","unlocalizedName":"item.minecraft.iron_pickaxe","localizedName":"Iron Pickaxe","maxStackSize":1,"maxDamage":250},{"id":"minecraft:iron_shovel","unlocalizedName":"item.minecraft.iron_shovel","localizedName":"Iron Shovel","maxStackSize":1,"maxDamage":250},{"id":"minecraft:iron_sword","unlocalizedName":"item.minecraft.iron_sword","localizedName":"Iron Sword","maxStackSize":1,"maxDamage":250},{"id":"minecraft:iron_trapdoor","unlocalizedName":"block.minecraft.iron_trapdoor","localizedName":"Iron Trapdoor","maxStackSize":64,"maxDamage":0},{"id":"minecraft:item_frame","unlocalizedName":"item.minecraft.item_frame","localizedName":"Item Frame","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jack_o_lantern","unlocalizedName":"block.minecraft.jack_o_lantern","localizedName":"Jack o'Lantern","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jigsaw","unlocalizedName":"block.minecraft.jigsaw","localizedName":"Jigsaw Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jukebox","unlocalizedName":"block.minecraft.jukebox","localizedName":"Jukebox","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_boat","unlocalizedName":"item.minecraft.jungle_boat","localizedName":"Jungle Boat","maxStackSize":1,"maxDamage":0},{"id":"minecraft:jungle_button","unlocalizedName":"block.minecraft.jungle_button","localizedName":"Jungle Button","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_door","unlocalizedName":"block.minecraft.jungle_door","localizedName":"Jungle Door","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_fence","unlocalizedName":"block.minecraft.jungle_fence","localizedName":"Jungle Fence","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_fence_gate","unlocalizedName":"block.minecraft.jungle_fence_gate","localizedName":"Jungle Fence Gate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_leaves","unlocalizedName":"block.minecraft.jungle_leaves","localizedName":"Jungle Leaves","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_log","unlocalizedName":"block.minecraft.jungle_log","localizedName":"Jungle Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_planks","unlocalizedName":"block.minecraft.jungle_planks","localizedName":"Jungle Planks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_pressure_plate","unlocalizedName":"block.minecraft.jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_sapling","unlocalizedName":"block.minecraft.jungle_sapling","localizedName":"Jungle Sapling","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_sign","unlocalizedName":"block.minecraft.jungle_sign","localizedName":"Jungle Sign","maxStackSize":16,"maxDamage":0},{"id":"minecraft:jungle_slab","unlocalizedName":"block.minecraft.jungle_slab","localizedName":"Jungle Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_stairs","unlocalizedName":"block.minecraft.jungle_stairs","localizedName":"Jungle Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_trapdoor","unlocalizedName":"block.minecraft.jungle_trapdoor","localizedName":"Jungle Trapdoor","maxStackSize":64,"maxDamage":0},{"id":"minecraft:jungle_wood","unlocalizedName":"block.minecraft.jungle_wood","localizedName":"Jungle Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:kelp","unlocalizedName":"block.minecraft.kelp","localizedName":"Kelp","maxStackSize":64,"maxDamage":0},{"id":"minecraft:knowledge_book","unlocalizedName":"item.minecraft.knowledge_book","localizedName":"Knowledge Book","maxStackSize":1,"maxDamage":0},{"id":"minecraft:ladder","unlocalizedName":"block.minecraft.ladder","localizedName":"Ladder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lantern","unlocalizedName":"block.minecraft.lantern","localizedName":"Lantern","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lapis_block","unlocalizedName":"block.minecraft.lapis_block","localizedName":"Lapis Lazuli Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lapis_lazuli","unlocalizedName":"item.minecraft.lapis_lazuli","localizedName":"Lapis Lazuli","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lapis_ore","unlocalizedName":"block.minecraft.lapis_ore","localizedName":"Lapis Lazuli Ore","maxStackSize":64,"maxDamage":0},{"id":"minecraft:large_fern","unlocalizedName":"block.minecraft.large_fern","localizedName":"Large Fern","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lava_bucket","unlocalizedName":"item.minecraft.lava_bucket","localizedName":"Lava Bucket","maxStackSize":1,"maxDamage":0},{"id":"minecraft:lead","unlocalizedName":"item.minecraft.lead","localizedName":"Lead","maxStackSize":64,"maxDamage":0},{"id":"minecraft:leather","unlocalizedName":"item.minecraft.leather","localizedName":"Leather","maxStackSize":64,"maxDamage":0},{"id":"minecraft:leather_boots","unlocalizedName":"item.minecraft.leather_boots","localizedName":"Leather Boots","maxStackSize":1,"maxDamage":65},{"id":"minecraft:leather_chestplate","unlocalizedName":"item.minecraft.leather_chestplate","localizedName":"Leather Tunic","maxStackSize":1,"maxDamage":80},{"id":"minecraft:leather_helmet","unlocalizedName":"item.minecraft.leather_helmet","localizedName":"Leather Cap","maxStackSize":1,"maxDamage":55},{"id":"minecraft:leather_horse_armor","unlocalizedName":"item.minecraft.leather_horse_armor","localizedName":"Leather Horse Armor","maxStackSize":1,"maxDamage":0},{"id":"minecraft:leather_leggings","unlocalizedName":"item.minecraft.leather_leggings","localizedName":"Leather Pants","maxStackSize":1,"maxDamage":75},{"id":"minecraft:lectern","unlocalizedName":"block.minecraft.lectern","localizedName":"Lectern","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lever","unlocalizedName":"block.minecraft.lever","localizedName":"Lever","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_blue_banner","unlocalizedName":"block.minecraft.light_blue_banner","localizedName":"Light Blue Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:light_blue_bed","unlocalizedName":"block.minecraft.light_blue_bed","localizedName":"Light Blue Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:light_blue_carpet","unlocalizedName":"block.minecraft.light_blue_carpet","localizedName":"Light Blue Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_blue_concrete","unlocalizedName":"block.minecraft.light_blue_concrete","localizedName":"Light Blue Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_blue_concrete_powder","unlocalizedName":"block.minecraft.light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_blue_dye","unlocalizedName":"item.minecraft.light_blue_dye","localizedName":"Light Blue Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_blue_glazed_terracotta","unlocalizedName":"block.minecraft.light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_blue_shulker_box","unlocalizedName":"block.minecraft.light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:light_blue_stained_glass","unlocalizedName":"block.minecraft.light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_blue_stained_glass_pane","unlocalizedName":"block.minecraft.light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_blue_terracotta","unlocalizedName":"block.minecraft.light_blue_terracotta","localizedName":"Light Blue Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_blue_wool","unlocalizedName":"block.minecraft.light_blue_wool","localizedName":"Light Blue Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_gray_banner","unlocalizedName":"block.minecraft.light_gray_banner","localizedName":"Light Gray Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:light_gray_bed","unlocalizedName":"block.minecraft.light_gray_bed","localizedName":"Light Gray Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:light_gray_carpet","unlocalizedName":"block.minecraft.light_gray_carpet","localizedName":"Light Gray Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_gray_concrete","unlocalizedName":"block.minecraft.light_gray_concrete","localizedName":"Light Gray Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_gray_concrete_powder","unlocalizedName":"block.minecraft.light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_gray_dye","unlocalizedName":"item.minecraft.light_gray_dye","localizedName":"Light Gray Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_gray_glazed_terracotta","unlocalizedName":"block.minecraft.light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_gray_shulker_box","unlocalizedName":"block.minecraft.light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:light_gray_stained_glass","unlocalizedName":"block.minecraft.light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_gray_stained_glass_pane","unlocalizedName":"block.minecraft.light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_gray_terracotta","unlocalizedName":"block.minecraft.light_gray_terracotta","localizedName":"Light Gray Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_gray_wool","unlocalizedName":"block.minecraft.light_gray_wool","localizedName":"Light Gray Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:light_weighted_pressure_plate","unlocalizedName":"block.minecraft.light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lilac","unlocalizedName":"block.minecraft.lilac","localizedName":"Lilac","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lily_of_the_valley","unlocalizedName":"block.minecraft.lily_of_the_valley","localizedName":"Lily of the Valley","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lily_pad","unlocalizedName":"block.minecraft.lily_pad","localizedName":"Lily Pad","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lime_banner","unlocalizedName":"block.minecraft.lime_banner","localizedName":"Lime Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:lime_bed","unlocalizedName":"block.minecraft.lime_bed","localizedName":"Lime Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:lime_carpet","unlocalizedName":"block.minecraft.lime_carpet","localizedName":"Lime Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lime_concrete","unlocalizedName":"block.minecraft.lime_concrete","localizedName":"Lime Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lime_concrete_powder","unlocalizedName":"block.minecraft.lime_concrete_powder","localizedName":"Lime Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lime_dye","unlocalizedName":"item.minecraft.lime_dye","localizedName":"Lime Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lime_glazed_terracotta","unlocalizedName":"block.minecraft.lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lime_shulker_box","unlocalizedName":"block.minecraft.lime_shulker_box","localizedName":"Lime Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:lime_stained_glass","unlocalizedName":"block.minecraft.lime_stained_glass","localizedName":"Lime Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lime_stained_glass_pane","unlocalizedName":"block.minecraft.lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lime_terracotta","unlocalizedName":"block.minecraft.lime_terracotta","localizedName":"Lime Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lime_wool","unlocalizedName":"block.minecraft.lime_wool","localizedName":"Lime Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:lingering_potion","unlocalizedName":"item.minecraft.lingering_potion.effect.water","localizedName":"Lingering Water Bottle","maxStackSize":1,"maxDamage":0},{"id":"minecraft:llama_spawn_egg","unlocalizedName":"item.minecraft.llama_spawn_egg","localizedName":"Llama Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:loom","unlocalizedName":"block.minecraft.loom","localizedName":"Loom","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magenta_banner","unlocalizedName":"block.minecraft.magenta_banner","localizedName":"Magenta Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:magenta_bed","unlocalizedName":"block.minecraft.magenta_bed","localizedName":"Magenta Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:magenta_carpet","unlocalizedName":"block.minecraft.magenta_carpet","localizedName":"Magenta Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magenta_concrete","unlocalizedName":"block.minecraft.magenta_concrete","localizedName":"Magenta Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magenta_concrete_powder","unlocalizedName":"block.minecraft.magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magenta_dye","unlocalizedName":"item.minecraft.magenta_dye","localizedName":"Magenta Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magenta_glazed_terracotta","unlocalizedName":"block.minecraft.magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magenta_shulker_box","unlocalizedName":"block.minecraft.magenta_shulker_box","localizedName":"Magenta Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:magenta_stained_glass","unlocalizedName":"block.minecraft.magenta_stained_glass","localizedName":"Magenta Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magenta_stained_glass_pane","unlocalizedName":"block.minecraft.magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magenta_terracotta","unlocalizedName":"block.minecraft.magenta_terracotta","localizedName":"Magenta Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magenta_wool","unlocalizedName":"block.minecraft.magenta_wool","localizedName":"Magenta Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magma_block","unlocalizedName":"block.minecraft.magma_block","localizedName":"Magma Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magma_cream","unlocalizedName":"item.minecraft.magma_cream","localizedName":"Magma Cream","maxStackSize":64,"maxDamage":0},{"id":"minecraft:magma_cube_spawn_egg","unlocalizedName":"item.minecraft.magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:map","unlocalizedName":"item.minecraft.map","localizedName":"Empty Map","maxStackSize":64,"maxDamage":0},{"id":"minecraft:melon","unlocalizedName":"block.minecraft.melon","localizedName":"Melon","maxStackSize":64,"maxDamage":0},{"id":"minecraft:melon_seeds","unlocalizedName":"item.minecraft.melon_seeds","localizedName":"Melon Seeds","maxStackSize":64,"maxDamage":0},{"id":"minecraft:melon_slice","unlocalizedName":"item.minecraft.melon_slice","localizedName":"Melon Slice","maxStackSize":64,"maxDamage":0},{"id":"minecraft:milk_bucket","unlocalizedName":"item.minecraft.milk_bucket","localizedName":"Milk Bucket","maxStackSize":1,"maxDamage":0},{"id":"minecraft:minecart","unlocalizedName":"item.minecraft.minecart","localizedName":"Minecart","maxStackSize":1,"maxDamage":0},{"id":"minecraft:mojang_banner_pattern","unlocalizedName":"item.minecraft.mojang_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"maxDamage":0},{"id":"minecraft:mooshroom_spawn_egg","unlocalizedName":"item.minecraft.mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mossy_cobblestone","unlocalizedName":"block.minecraft.mossy_cobblestone","localizedName":"Mossy Cobblestone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mossy_cobblestone_slab","unlocalizedName":"block.minecraft.mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mossy_cobblestone_stairs","unlocalizedName":"block.minecraft.mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mossy_cobblestone_wall","unlocalizedName":"block.minecraft.mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mossy_stone_brick_slab","unlocalizedName":"block.minecraft.mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mossy_stone_brick_stairs","unlocalizedName":"block.minecraft.mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mossy_stone_brick_wall","unlocalizedName":"block.minecraft.mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mossy_stone_bricks","unlocalizedName":"block.minecraft.mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mule_spawn_egg","unlocalizedName":"item.minecraft.mule_spawn_egg","localizedName":"Mule Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mushroom_stem","unlocalizedName":"block.minecraft.mushroom_stem","localizedName":"Mushroom Stem","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mushroom_stew","unlocalizedName":"item.minecraft.mushroom_stew","localizedName":"Mushroom Stew","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_11","unlocalizedName":"item.minecraft.music_disc_11","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_13","unlocalizedName":"item.minecraft.music_disc_13","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_blocks","unlocalizedName":"item.minecraft.music_disc_blocks","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_cat","unlocalizedName":"item.minecraft.music_disc_cat","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_chirp","unlocalizedName":"item.minecraft.music_disc_chirp","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_far","unlocalizedName":"item.minecraft.music_disc_far","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_mall","unlocalizedName":"item.minecraft.music_disc_mall","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_mellohi","unlocalizedName":"item.minecraft.music_disc_mellohi","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_stal","unlocalizedName":"item.minecraft.music_disc_stal","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_strad","unlocalizedName":"item.minecraft.music_disc_strad","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_wait","unlocalizedName":"item.minecraft.music_disc_wait","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:music_disc_ward","unlocalizedName":"item.minecraft.music_disc_ward","localizedName":"Music Disc","maxStackSize":1,"maxDamage":0},{"id":"minecraft:mutton","unlocalizedName":"item.minecraft.mutton","localizedName":"Raw Mutton","maxStackSize":64,"maxDamage":0},{"id":"minecraft:mycelium","unlocalizedName":"block.minecraft.mycelium","localizedName":"Mycelium","maxStackSize":64,"maxDamage":0},{"id":"minecraft:name_tag","unlocalizedName":"item.minecraft.name_tag","localizedName":"Name Tag","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nautilus_shell","unlocalizedName":"item.minecraft.nautilus_shell","localizedName":"Nautilus Shell","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nether_brick","unlocalizedName":"item.minecraft.nether_brick","localizedName":"Nether Brick","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nether_brick_fence","unlocalizedName":"block.minecraft.nether_brick_fence","localizedName":"Nether Brick Fence","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nether_brick_slab","unlocalizedName":"block.minecraft.nether_brick_slab","localizedName":"Nether Brick Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nether_brick_stairs","unlocalizedName":"block.minecraft.nether_brick_stairs","localizedName":"Nether Brick Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nether_brick_wall","unlocalizedName":"block.minecraft.nether_brick_wall","localizedName":"Nether Brick Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nether_bricks","unlocalizedName":"block.minecraft.nether_bricks","localizedName":"Nether Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nether_quartz_ore","unlocalizedName":"block.minecraft.nether_quartz_ore","localizedName":"Nether Quartz Ore","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nether_star","unlocalizedName":"item.minecraft.nether_star","localizedName":"Nether Star","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nether_wart","unlocalizedName":"item.minecraft.nether_wart","localizedName":"Nether Wart","maxStackSize":64,"maxDamage":0},{"id":"minecraft:nether_wart_block","unlocalizedName":"block.minecraft.nether_wart_block","localizedName":"Nether Wart Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:netherrack","unlocalizedName":"block.minecraft.netherrack","localizedName":"Netherrack","maxStackSize":64,"maxDamage":0},{"id":"minecraft:note_block","unlocalizedName":"block.minecraft.note_block","localizedName":"Note Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_boat","unlocalizedName":"item.minecraft.oak_boat","localizedName":"Oak Boat","maxStackSize":1,"maxDamage":0},{"id":"minecraft:oak_button","unlocalizedName":"block.minecraft.oak_button","localizedName":"Oak Button","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_door","unlocalizedName":"block.minecraft.oak_door","localizedName":"Oak Door","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_fence","unlocalizedName":"block.minecraft.oak_fence","localizedName":"Oak Fence","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_fence_gate","unlocalizedName":"block.minecraft.oak_fence_gate","localizedName":"Oak Fence Gate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_leaves","unlocalizedName":"block.minecraft.oak_leaves","localizedName":"Oak Leaves","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_log","unlocalizedName":"block.minecraft.oak_log","localizedName":"Oak Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_planks","unlocalizedName":"block.minecraft.oak_planks","localizedName":"Oak Planks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_pressure_plate","unlocalizedName":"block.minecraft.oak_pressure_plate","localizedName":"Oak Pressure Plate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_sapling","unlocalizedName":"block.minecraft.oak_sapling","localizedName":"Oak Sapling","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_sign","unlocalizedName":"block.minecraft.oak_sign","localizedName":"Oak Sign","maxStackSize":16,"maxDamage":0},{"id":"minecraft:oak_slab","unlocalizedName":"block.minecraft.oak_slab","localizedName":"Oak Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_stairs","unlocalizedName":"block.minecraft.oak_stairs","localizedName":"Oak Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_trapdoor","unlocalizedName":"block.minecraft.oak_trapdoor","localizedName":"Oak Trapdoor","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oak_wood","unlocalizedName":"block.minecraft.oak_wood","localizedName":"Oak Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:observer","unlocalizedName":"block.minecraft.observer","localizedName":"Observer","maxStackSize":64,"maxDamage":0},{"id":"minecraft:obsidian","unlocalizedName":"block.minecraft.obsidian","localizedName":"Obsidian","maxStackSize":64,"maxDamage":0},{"id":"minecraft:ocelot_spawn_egg","unlocalizedName":"item.minecraft.ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:orange_banner","unlocalizedName":"block.minecraft.orange_banner","localizedName":"Orange Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:orange_bed","unlocalizedName":"block.minecraft.orange_bed","localizedName":"Orange Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:orange_carpet","unlocalizedName":"block.minecraft.orange_carpet","localizedName":"Orange Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:orange_concrete","unlocalizedName":"block.minecraft.orange_concrete","localizedName":"Orange Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:orange_concrete_powder","unlocalizedName":"block.minecraft.orange_concrete_powder","localizedName":"Orange Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:orange_dye","unlocalizedName":"item.minecraft.orange_dye","localizedName":"Orange Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:orange_glazed_terracotta","unlocalizedName":"block.minecraft.orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:orange_shulker_box","unlocalizedName":"block.minecraft.orange_shulker_box","localizedName":"Orange Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:orange_stained_glass","unlocalizedName":"block.minecraft.orange_stained_glass","localizedName":"Orange Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:orange_stained_glass_pane","unlocalizedName":"block.minecraft.orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:orange_terracotta","unlocalizedName":"block.minecraft.orange_terracotta","localizedName":"Orange Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:orange_tulip","unlocalizedName":"block.minecraft.orange_tulip","localizedName":"Orange Tulip","maxStackSize":64,"maxDamage":0},{"id":"minecraft:orange_wool","unlocalizedName":"block.minecraft.orange_wool","localizedName":"Orange Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:oxeye_daisy","unlocalizedName":"block.minecraft.oxeye_daisy","localizedName":"Oxeye Daisy","maxStackSize":64,"maxDamage":0},{"id":"minecraft:packed_ice","unlocalizedName":"block.minecraft.packed_ice","localizedName":"Packed Ice","maxStackSize":64,"maxDamage":0},{"id":"minecraft:painting","unlocalizedName":"item.minecraft.painting","localizedName":"Painting","maxStackSize":64,"maxDamage":0},{"id":"minecraft:panda_spawn_egg","unlocalizedName":"item.minecraft.panda_spawn_egg","localizedName":"Panda Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:paper","unlocalizedName":"item.minecraft.paper","localizedName":"Paper","maxStackSize":64,"maxDamage":0},{"id":"minecraft:parrot_spawn_egg","unlocalizedName":"item.minecraft.parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:peony","unlocalizedName":"block.minecraft.peony","localizedName":"Peony","maxStackSize":64,"maxDamage":0},{"id":"minecraft:petrified_oak_slab","unlocalizedName":"block.minecraft.petrified_oak_slab","localizedName":"Petrified Oak Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:phantom_membrane","unlocalizedName":"item.minecraft.phantom_membrane","localizedName":"Phantom Membrane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:phantom_spawn_egg","unlocalizedName":"item.minecraft.phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pig_spawn_egg","unlocalizedName":"item.minecraft.pig_spawn_egg","localizedName":"Pig Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pillager_spawn_egg","unlocalizedName":"item.minecraft.pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pink_banner","unlocalizedName":"block.minecraft.pink_banner","localizedName":"Pink Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:pink_bed","unlocalizedName":"block.minecraft.pink_bed","localizedName":"Pink Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:pink_carpet","unlocalizedName":"block.minecraft.pink_carpet","localizedName":"Pink Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pink_concrete","unlocalizedName":"block.minecraft.pink_concrete","localizedName":"Pink Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pink_concrete_powder","unlocalizedName":"block.minecraft.pink_concrete_powder","localizedName":"Pink Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pink_dye","unlocalizedName":"item.minecraft.pink_dye","localizedName":"Pink Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pink_glazed_terracotta","unlocalizedName":"block.minecraft.pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pink_shulker_box","unlocalizedName":"block.minecraft.pink_shulker_box","localizedName":"Pink Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:pink_stained_glass","unlocalizedName":"block.minecraft.pink_stained_glass","localizedName":"Pink Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pink_stained_glass_pane","unlocalizedName":"block.minecraft.pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pink_terracotta","unlocalizedName":"block.minecraft.pink_terracotta","localizedName":"Pink Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pink_tulip","unlocalizedName":"block.minecraft.pink_tulip","localizedName":"Pink Tulip","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pink_wool","unlocalizedName":"block.minecraft.pink_wool","localizedName":"Pink Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:piston","unlocalizedName":"block.minecraft.piston","localizedName":"Piston","maxStackSize":64,"maxDamage":0},{"id":"minecraft:player_head","unlocalizedName":"block.minecraft.player_head","localizedName":"Player Head","maxStackSize":64,"maxDamage":0},{"id":"minecraft:podzol","unlocalizedName":"block.minecraft.podzol","localizedName":"Podzol","maxStackSize":64,"maxDamage":0},{"id":"minecraft:poisonous_potato","unlocalizedName":"item.minecraft.poisonous_potato","localizedName":"Poisonous Potato","maxStackSize":64,"maxDamage":0},{"id":"minecraft:polar_bear_spawn_egg","unlocalizedName":"item.minecraft.polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:polished_andesite","unlocalizedName":"block.minecraft.polished_andesite","localizedName":"Polished Andesite","maxStackSize":64,"maxDamage":0},{"id":"minecraft:polished_andesite_slab","unlocalizedName":"block.minecraft.polished_andesite_slab","localizedName":"Polished Andesite Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:polished_andesite_stairs","unlocalizedName":"block.minecraft.polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:polished_diorite","unlocalizedName":"block.minecraft.polished_diorite","localizedName":"Polished Diorite","maxStackSize":64,"maxDamage":0},{"id":"minecraft:polished_diorite_slab","unlocalizedName":"block.minecraft.polished_diorite_slab","localizedName":"Polished Diorite Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:polished_diorite_stairs","unlocalizedName":"block.minecraft.polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:polished_granite","unlocalizedName":"block.minecraft.polished_granite","localizedName":"Polished Granite","maxStackSize":64,"maxDamage":0},{"id":"minecraft:polished_granite_slab","unlocalizedName":"block.minecraft.polished_granite_slab","localizedName":"Polished Granite Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:polished_granite_stairs","unlocalizedName":"block.minecraft.polished_granite_stairs","localizedName":"Polished Granite Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:popped_chorus_fruit","unlocalizedName":"item.minecraft.popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxStackSize":64,"maxDamage":0},{"id":"minecraft:poppy","unlocalizedName":"block.minecraft.poppy","localizedName":"Poppy","maxStackSize":64,"maxDamage":0},{"id":"minecraft:porkchop","unlocalizedName":"item.minecraft.porkchop","localizedName":"Raw Porkchop","maxStackSize":64,"maxDamage":0},{"id":"minecraft:potato","unlocalizedName":"item.minecraft.potato","localizedName":"Potato","maxStackSize":64,"maxDamage":0},{"id":"minecraft:potion","unlocalizedName":"item.minecraft.potion.effect.water","localizedName":"Water Bottle","maxStackSize":1,"maxDamage":0},{"id":"minecraft:powered_rail","unlocalizedName":"block.minecraft.powered_rail","localizedName":"Powered Rail","maxStackSize":64,"maxDamage":0},{"id":"minecraft:prismarine","unlocalizedName":"block.minecraft.prismarine","localizedName":"Prismarine","maxStackSize":64,"maxDamage":0},{"id":"minecraft:prismarine_brick_slab","unlocalizedName":"block.minecraft.prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:prismarine_brick_stairs","unlocalizedName":"block.minecraft.prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:prismarine_bricks","unlocalizedName":"block.minecraft.prismarine_bricks","localizedName":"Prismarine Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:prismarine_crystals","unlocalizedName":"item.minecraft.prismarine_crystals","localizedName":"Prismarine Crystals","maxStackSize":64,"maxDamage":0},{"id":"minecraft:prismarine_shard","unlocalizedName":"item.minecraft.prismarine_shard","localizedName":"Prismarine Shard","maxStackSize":64,"maxDamage":0},{"id":"minecraft:prismarine_slab","unlocalizedName":"block.minecraft.prismarine_slab","localizedName":"Prismarine Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:prismarine_stairs","unlocalizedName":"block.minecraft.prismarine_stairs","localizedName":"Prismarine Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:prismarine_wall","unlocalizedName":"block.minecraft.prismarine_wall","localizedName":"Prismarine Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pufferfish","unlocalizedName":"item.minecraft.pufferfish","localizedName":"Pufferfish","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pufferfish_bucket","unlocalizedName":"item.minecraft.pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxStackSize":1,"maxDamage":0},{"id":"minecraft:pufferfish_spawn_egg","unlocalizedName":"item.minecraft.pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pumpkin","unlocalizedName":"block.minecraft.pumpkin","localizedName":"Pumpkin","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pumpkin_pie","unlocalizedName":"item.minecraft.pumpkin_pie","localizedName":"Pumpkin Pie","maxStackSize":64,"maxDamage":0},{"id":"minecraft:pumpkin_seeds","unlocalizedName":"item.minecraft.pumpkin_seeds","localizedName":"Pumpkin Seeds","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purple_banner","unlocalizedName":"block.minecraft.purple_banner","localizedName":"Purple Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:purple_bed","unlocalizedName":"block.minecraft.purple_bed","localizedName":"Purple Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:purple_carpet","unlocalizedName":"block.minecraft.purple_carpet","localizedName":"Purple Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purple_concrete","unlocalizedName":"block.minecraft.purple_concrete","localizedName":"Purple Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purple_concrete_powder","unlocalizedName":"block.minecraft.purple_concrete_powder","localizedName":"Purple Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purple_dye","unlocalizedName":"item.minecraft.purple_dye","localizedName":"Purple Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purple_glazed_terracotta","unlocalizedName":"block.minecraft.purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purple_shulker_box","unlocalizedName":"block.minecraft.purple_shulker_box","localizedName":"Purple Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:purple_stained_glass","unlocalizedName":"block.minecraft.purple_stained_glass","localizedName":"Purple Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purple_stained_glass_pane","unlocalizedName":"block.minecraft.purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purple_terracotta","unlocalizedName":"block.minecraft.purple_terracotta","localizedName":"Purple Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purple_wool","unlocalizedName":"block.minecraft.purple_wool","localizedName":"Purple Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purpur_block","unlocalizedName":"block.minecraft.purpur_block","localizedName":"Purpur Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purpur_pillar","unlocalizedName":"block.minecraft.purpur_pillar","localizedName":"Purpur Pillar","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purpur_slab","unlocalizedName":"block.minecraft.purpur_slab","localizedName":"Purpur Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:purpur_stairs","unlocalizedName":"block.minecraft.purpur_stairs","localizedName":"Purpur Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:quartz","unlocalizedName":"item.minecraft.quartz","localizedName":"Nether Quartz","maxStackSize":64,"maxDamage":0},{"id":"minecraft:quartz_block","unlocalizedName":"block.minecraft.quartz_block","localizedName":"Block of Quartz","maxStackSize":64,"maxDamage":0},{"id":"minecraft:quartz_pillar","unlocalizedName":"block.minecraft.quartz_pillar","localizedName":"Quartz Pillar","maxStackSize":64,"maxDamage":0},{"id":"minecraft:quartz_slab","unlocalizedName":"block.minecraft.quartz_slab","localizedName":"Quartz Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:quartz_stairs","unlocalizedName":"block.minecraft.quartz_stairs","localizedName":"Quartz Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:rabbit","unlocalizedName":"item.minecraft.rabbit","localizedName":"Raw Rabbit","maxStackSize":64,"maxDamage":0},{"id":"minecraft:rabbit_foot","unlocalizedName":"item.minecraft.rabbit_foot","localizedName":"Rabbit's Foot","maxStackSize":64,"maxDamage":0},{"id":"minecraft:rabbit_hide","unlocalizedName":"item.minecraft.rabbit_hide","localizedName":"Rabbit Hide","maxStackSize":64,"maxDamage":0},{"id":"minecraft:rabbit_spawn_egg","unlocalizedName":"item.minecraft.rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:rabbit_stew","unlocalizedName":"item.minecraft.rabbit_stew","localizedName":"Rabbit Stew","maxStackSize":1,"maxDamage":0},{"id":"minecraft:rail","unlocalizedName":"block.minecraft.rail","localizedName":"Rail","maxStackSize":64,"maxDamage":0},{"id":"minecraft:ravager_spawn_egg","unlocalizedName":"item.minecraft.ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_banner","unlocalizedName":"block.minecraft.red_banner","localizedName":"Red Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:red_bed","unlocalizedName":"block.minecraft.red_bed","localizedName":"Red Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:red_carpet","unlocalizedName":"block.minecraft.red_carpet","localizedName":"Red Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_concrete","unlocalizedName":"block.minecraft.red_concrete","localizedName":"Red Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_concrete_powder","unlocalizedName":"block.minecraft.red_concrete_powder","localizedName":"Red Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_dye","unlocalizedName":"item.minecraft.red_dye","localizedName":"Red Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_glazed_terracotta","unlocalizedName":"block.minecraft.red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_mushroom","unlocalizedName":"block.minecraft.red_mushroom","localizedName":"Red Mushroom","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_mushroom_block","unlocalizedName":"block.minecraft.red_mushroom_block","localizedName":"Red Mushroom Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_nether_brick_slab","unlocalizedName":"block.minecraft.red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_nether_brick_stairs","unlocalizedName":"block.minecraft.red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_nether_brick_wall","unlocalizedName":"block.minecraft.red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_nether_bricks","unlocalizedName":"block.minecraft.red_nether_bricks","localizedName":"Red Nether Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_sand","unlocalizedName":"block.minecraft.red_sand","localizedName":"Red Sand","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_sandstone","unlocalizedName":"block.minecraft.red_sandstone","localizedName":"Red Sandstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_sandstone_slab","unlocalizedName":"block.minecraft.red_sandstone_slab","localizedName":"Red Sandstone Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_sandstone_stairs","unlocalizedName":"block.minecraft.red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_sandstone_wall","unlocalizedName":"block.minecraft.red_sandstone_wall","localizedName":"Red Sandstone Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_shulker_box","unlocalizedName":"block.minecraft.red_shulker_box","localizedName":"Red Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:red_stained_glass","unlocalizedName":"block.minecraft.red_stained_glass","localizedName":"Red Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_stained_glass_pane","unlocalizedName":"block.minecraft.red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_terracotta","unlocalizedName":"block.minecraft.red_terracotta","localizedName":"Red Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_tulip","unlocalizedName":"block.minecraft.red_tulip","localizedName":"Red Tulip","maxStackSize":64,"maxDamage":0},{"id":"minecraft:red_wool","unlocalizedName":"block.minecraft.red_wool","localizedName":"Red Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:redstone","unlocalizedName":"item.minecraft.redstone","localizedName":"Redstone Dust","maxStackSize":64,"maxDamage":0},{"id":"minecraft:redstone_block","unlocalizedName":"block.minecraft.redstone_block","localizedName":"Block of Redstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:redstone_lamp","unlocalizedName":"block.minecraft.redstone_lamp","localizedName":"Redstone Lamp","maxStackSize":64,"maxDamage":0},{"id":"minecraft:redstone_ore","unlocalizedName":"block.minecraft.redstone_ore","localizedName":"Redstone Ore","maxStackSize":64,"maxDamage":0},{"id":"minecraft:redstone_torch","unlocalizedName":"block.minecraft.redstone_torch","localizedName":"Redstone Torch","maxStackSize":64,"maxDamage":0},{"id":"minecraft:repeater","unlocalizedName":"block.minecraft.repeater","localizedName":"Redstone Repeater","maxStackSize":64,"maxDamage":0},{"id":"minecraft:repeating_command_block","unlocalizedName":"block.minecraft.repeating_command_block","localizedName":"Repeating Command Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:rose_bush","unlocalizedName":"block.minecraft.rose_bush","localizedName":"Rose Bush","maxStackSize":64,"maxDamage":0},{"id":"minecraft:rotten_flesh","unlocalizedName":"item.minecraft.rotten_flesh","localizedName":"Rotten Flesh","maxStackSize":64,"maxDamage":0},{"id":"minecraft:saddle","unlocalizedName":"item.minecraft.saddle","localizedName":"Saddle","maxStackSize":1,"maxDamage":0},{"id":"minecraft:salmon","unlocalizedName":"item.minecraft.salmon","localizedName":"Raw Salmon","maxStackSize":64,"maxDamage":0},{"id":"minecraft:salmon_bucket","unlocalizedName":"item.minecraft.salmon_bucket","localizedName":"Bucket of Salmon","maxStackSize":1,"maxDamage":0},{"id":"minecraft:salmon_spawn_egg","unlocalizedName":"item.minecraft.salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sand","unlocalizedName":"block.minecraft.sand","localizedName":"Sand","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sandstone","unlocalizedName":"block.minecraft.sandstone","localizedName":"Sandstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sandstone_slab","unlocalizedName":"block.minecraft.sandstone_slab","localizedName":"Sandstone Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sandstone_stairs","unlocalizedName":"block.minecraft.sandstone_stairs","localizedName":"Sandstone Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sandstone_wall","unlocalizedName":"block.minecraft.sandstone_wall","localizedName":"Sandstone Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:scaffolding","unlocalizedName":"block.minecraft.scaffolding","localizedName":"Scaffolding","maxStackSize":64,"maxDamage":0},{"id":"minecraft:scute","unlocalizedName":"item.minecraft.scute","localizedName":"Scute","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sea_lantern","unlocalizedName":"block.minecraft.sea_lantern","localizedName":"Sea Lantern","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sea_pickle","unlocalizedName":"block.minecraft.sea_pickle","localizedName":"Sea Pickle","maxStackSize":64,"maxDamage":0},{"id":"minecraft:seagrass","unlocalizedName":"block.minecraft.seagrass","localizedName":"Seagrass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:shears","unlocalizedName":"item.minecraft.shears","localizedName":"Shears","maxStackSize":1,"maxDamage":238},{"id":"minecraft:sheep_spawn_egg","unlocalizedName":"item.minecraft.sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:shield","unlocalizedName":"item.minecraft.shield","localizedName":"Shield","maxStackSize":1,"maxDamage":336},{"id":"minecraft:shulker_box","unlocalizedName":"block.minecraft.shulker_box","localizedName":"Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:shulker_shell","unlocalizedName":"item.minecraft.shulker_shell","localizedName":"Shulker Shell","maxStackSize":64,"maxDamage":0},{"id":"minecraft:shulker_spawn_egg","unlocalizedName":"item.minecraft.shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:silverfish_spawn_egg","unlocalizedName":"item.minecraft.silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:skeleton_horse_spawn_egg","unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:skeleton_skull","unlocalizedName":"block.minecraft.skeleton_skull","localizedName":"Skeleton Skull","maxStackSize":64,"maxDamage":0},{"id":"minecraft:skeleton_spawn_egg","unlocalizedName":"item.minecraft.skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:skull_banner_pattern","unlocalizedName":"item.minecraft.skull_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"maxDamage":0},{"id":"minecraft:slime_ball","unlocalizedName":"item.minecraft.slime_ball","localizedName":"Slimeball","maxStackSize":64,"maxDamage":0},{"id":"minecraft:slime_block","unlocalizedName":"block.minecraft.slime_block","localizedName":"Slime Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:slime_spawn_egg","unlocalizedName":"item.minecraft.slime_spawn_egg","localizedName":"Slime Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smithing_table","unlocalizedName":"block.minecraft.smithing_table","localizedName":"Smithing Table","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smoker","unlocalizedName":"block.minecraft.smoker","localizedName":"Smoker","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_quartz","unlocalizedName":"block.minecraft.smooth_quartz","localizedName":"Smooth Quartz","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_quartz_slab","unlocalizedName":"block.minecraft.smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_quartz_stairs","unlocalizedName":"block.minecraft.smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_red_sandstone","unlocalizedName":"block.minecraft.smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_red_sandstone_slab","unlocalizedName":"block.minecraft.smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_red_sandstone_stairs","unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_sandstone","unlocalizedName":"block.minecraft.smooth_sandstone","localizedName":"Smooth Sandstone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_sandstone_slab","unlocalizedName":"block.minecraft.smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_sandstone_stairs","unlocalizedName":"block.minecraft.smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_stone","unlocalizedName":"block.minecraft.smooth_stone","localizedName":"Smooth Stone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:smooth_stone_slab","unlocalizedName":"block.minecraft.smooth_stone_slab","localizedName":"Smooth Stone Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:snow","unlocalizedName":"block.minecraft.snow","localizedName":"Snow","maxStackSize":64,"maxDamage":0},{"id":"minecraft:snow_block","unlocalizedName":"block.minecraft.snow_block","localizedName":"Snow Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:snowball","unlocalizedName":"item.minecraft.snowball","localizedName":"Snowball","maxStackSize":16,"maxDamage":0},{"id":"minecraft:soul_sand","unlocalizedName":"block.minecraft.soul_sand","localizedName":"Soul Sand","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spawner","unlocalizedName":"block.minecraft.spawner","localizedName":"Spawner","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spectral_arrow","unlocalizedName":"item.minecraft.spectral_arrow","localizedName":"Spectral Arrow","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spider_eye","unlocalizedName":"item.minecraft.spider_eye","localizedName":"Spider Eye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spider_spawn_egg","unlocalizedName":"item.minecraft.spider_spawn_egg","localizedName":"Spider Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:splash_potion","unlocalizedName":"item.minecraft.splash_potion.effect.water","localizedName":"Splash Water Bottle","maxStackSize":1,"maxDamage":0},{"id":"minecraft:sponge","unlocalizedName":"block.minecraft.sponge","localizedName":"Sponge","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_boat","unlocalizedName":"item.minecraft.spruce_boat","localizedName":"Spruce Boat","maxStackSize":1,"maxDamage":0},{"id":"minecraft:spruce_button","unlocalizedName":"block.minecraft.spruce_button","localizedName":"Spruce Button","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_door","unlocalizedName":"block.minecraft.spruce_door","localizedName":"Spruce Door","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_fence","unlocalizedName":"block.minecraft.spruce_fence","localizedName":"Spruce Fence","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_fence_gate","unlocalizedName":"block.minecraft.spruce_fence_gate","localizedName":"Spruce Fence Gate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_leaves","unlocalizedName":"block.minecraft.spruce_leaves","localizedName":"Spruce Leaves","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_log","unlocalizedName":"block.minecraft.spruce_log","localizedName":"Spruce Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_planks","unlocalizedName":"block.minecraft.spruce_planks","localizedName":"Spruce Planks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_pressure_plate","unlocalizedName":"block.minecraft.spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_sapling","unlocalizedName":"block.minecraft.spruce_sapling","localizedName":"Spruce Sapling","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_sign","unlocalizedName":"block.minecraft.spruce_sign","localizedName":"Spruce Sign","maxStackSize":16,"maxDamage":0},{"id":"minecraft:spruce_slab","unlocalizedName":"block.minecraft.spruce_slab","localizedName":"Spruce Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_stairs","unlocalizedName":"block.minecraft.spruce_stairs","localizedName":"Spruce Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_trapdoor","unlocalizedName":"block.minecraft.spruce_trapdoor","localizedName":"Spruce Trapdoor","maxStackSize":64,"maxDamage":0},{"id":"minecraft:spruce_wood","unlocalizedName":"block.minecraft.spruce_wood","localizedName":"Spruce Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:squid_spawn_egg","unlocalizedName":"item.minecraft.squid_spawn_egg","localizedName":"Squid Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stick","unlocalizedName":"item.minecraft.stick","localizedName":"Stick","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sticky_piston","unlocalizedName":"block.minecraft.sticky_piston","localizedName":"Sticky Piston","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stone","unlocalizedName":"block.minecraft.stone","localizedName":"Stone","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stone_axe","unlocalizedName":"item.minecraft.stone_axe","localizedName":"Stone Axe","maxStackSize":1,"maxDamage":131},{"id":"minecraft:stone_brick_slab","unlocalizedName":"block.minecraft.stone_brick_slab","localizedName":"Stone Brick Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stone_brick_stairs","unlocalizedName":"block.minecraft.stone_brick_stairs","localizedName":"Stone Brick Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stone_brick_wall","unlocalizedName":"block.minecraft.stone_brick_wall","localizedName":"Stone Brick Wall","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stone_bricks","unlocalizedName":"block.minecraft.stone_bricks","localizedName":"Stone Bricks","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stone_button","unlocalizedName":"block.minecraft.stone_button","localizedName":"Stone Button","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stone_hoe","unlocalizedName":"item.minecraft.stone_hoe","localizedName":"Stone Hoe","maxStackSize":1,"maxDamage":131},{"id":"minecraft:stone_pickaxe","unlocalizedName":"item.minecraft.stone_pickaxe","localizedName":"Stone Pickaxe","maxStackSize":1,"maxDamage":131},{"id":"minecraft:stone_pressure_plate","unlocalizedName":"block.minecraft.stone_pressure_plate","localizedName":"Stone Pressure Plate","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stone_shovel","unlocalizedName":"item.minecraft.stone_shovel","localizedName":"Stone Shovel","maxStackSize":1,"maxDamage":131},{"id":"minecraft:stone_slab","unlocalizedName":"block.minecraft.stone_slab","localizedName":"Stone Slab","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stone_stairs","unlocalizedName":"block.minecraft.stone_stairs","localizedName":"Stone Stairs","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stone_sword","unlocalizedName":"item.minecraft.stone_sword","localizedName":"Stone Sword","maxStackSize":1,"maxDamage":131},{"id":"minecraft:stonecutter","unlocalizedName":"block.minecraft.stonecutter","localizedName":"Stonecutter","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stray_spawn_egg","unlocalizedName":"item.minecraft.stray_spawn_egg","localizedName":"Stray Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:string","unlocalizedName":"item.minecraft.string","localizedName":"String","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_acacia_log","unlocalizedName":"block.minecraft.stripped_acacia_log","localizedName":"Stripped Acacia Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_acacia_wood","unlocalizedName":"block.minecraft.stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_birch_log","unlocalizedName":"block.minecraft.stripped_birch_log","localizedName":"Stripped Birch Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_birch_wood","unlocalizedName":"block.minecraft.stripped_birch_wood","localizedName":"Stripped Birch Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_dark_oak_log","unlocalizedName":"block.minecraft.stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_dark_oak_wood","unlocalizedName":"block.minecraft.stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_jungle_log","unlocalizedName":"block.minecraft.stripped_jungle_log","localizedName":"Stripped Jungle Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_jungle_wood","unlocalizedName":"block.minecraft.stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_oak_log","unlocalizedName":"block.minecraft.stripped_oak_log","localizedName":"Stripped Oak Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_oak_wood","unlocalizedName":"block.minecraft.stripped_oak_wood","localizedName":"Stripped Oak Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_spruce_log","unlocalizedName":"block.minecraft.stripped_spruce_log","localizedName":"Stripped Spruce Log","maxStackSize":64,"maxDamage":0},{"id":"minecraft:stripped_spruce_wood","unlocalizedName":"block.minecraft.stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxStackSize":64,"maxDamage":0},{"id":"minecraft:structure_block","unlocalizedName":"block.minecraft.structure_block","localizedName":"Structure Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:structure_void","unlocalizedName":"block.minecraft.structure_void","localizedName":"Structure Void","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sugar","unlocalizedName":"item.minecraft.sugar","localizedName":"Sugar","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sugar_cane","unlocalizedName":"block.minecraft.sugar_cane","localizedName":"Sugar Cane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:sunflower","unlocalizedName":"block.minecraft.sunflower","localizedName":"Sunflower","maxStackSize":64,"maxDamage":0},{"id":"minecraft:suspicious_stew","unlocalizedName":"item.minecraft.suspicious_stew","localizedName":"Suspicious Stew","maxStackSize":1,"maxDamage":0},{"id":"minecraft:sweet_berries","unlocalizedName":"item.minecraft.sweet_berries","localizedName":"Sweet Berries","maxStackSize":64,"maxDamage":0},{"id":"minecraft:tall_grass","unlocalizedName":"block.minecraft.tall_grass","localizedName":"Tall Grass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:terracotta","unlocalizedName":"block.minecraft.terracotta","localizedName":"Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:tipped_arrow","unlocalizedName":"item.minecraft.tipped_arrow.effect.poison","localizedName":"Arrow of Poison","maxStackSize":64,"maxDamage":0},{"id":"minecraft:tnt","unlocalizedName":"block.minecraft.tnt","localizedName":"TNT","maxStackSize":64,"maxDamage":0},{"id":"minecraft:tnt_minecart","unlocalizedName":"item.minecraft.tnt_minecart","localizedName":"Minecart with TNT","maxStackSize":1,"maxDamage":0},{"id":"minecraft:torch","unlocalizedName":"block.minecraft.torch","localizedName":"Torch","maxStackSize":64,"maxDamage":0},{"id":"minecraft:totem_of_undying","unlocalizedName":"item.minecraft.totem_of_undying","localizedName":"Totem of Undying","maxStackSize":1,"maxDamage":0},{"id":"minecraft:trader_llama_spawn_egg","unlocalizedName":"item.minecraft.trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:trapped_chest","unlocalizedName":"block.minecraft.trapped_chest","localizedName":"Trapped Chest","maxStackSize":64,"maxDamage":0},{"id":"minecraft:trident","unlocalizedName":"item.minecraft.trident","localizedName":"Trident","maxStackSize":1,"maxDamage":250},{"id":"minecraft:tripwire_hook","unlocalizedName":"block.minecraft.tripwire_hook","localizedName":"Tripwire Hook","maxStackSize":64,"maxDamage":0},{"id":"minecraft:tropical_fish","unlocalizedName":"item.minecraft.tropical_fish","localizedName":"Tropical Fish","maxStackSize":64,"maxDamage":0},{"id":"minecraft:tropical_fish_bucket","unlocalizedName":"item.minecraft.tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxStackSize":1,"maxDamage":0},{"id":"minecraft:tropical_fish_spawn_egg","unlocalizedName":"item.minecraft.tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:tube_coral","unlocalizedName":"block.minecraft.tube_coral","localizedName":"Tube Coral","maxStackSize":64,"maxDamage":0},{"id":"minecraft:tube_coral_block","unlocalizedName":"block.minecraft.tube_coral_block","localizedName":"Tube Coral Block","maxStackSize":64,"maxDamage":0},{"id":"minecraft:tube_coral_fan","unlocalizedName":"block.minecraft.tube_coral_fan","localizedName":"Tube Coral Fan","maxStackSize":64,"maxDamage":0},{"id":"minecraft:turtle_egg","unlocalizedName":"block.minecraft.turtle_egg","localizedName":"Turtle Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:turtle_helmet","unlocalizedName":"item.minecraft.turtle_helmet","localizedName":"Turtle Shell","maxStackSize":1,"maxDamage":275},{"id":"minecraft:turtle_spawn_egg","unlocalizedName":"item.minecraft.turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:vex_spawn_egg","unlocalizedName":"item.minecraft.vex_spawn_egg","localizedName":"Vex Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:villager_spawn_egg","unlocalizedName":"item.minecraft.villager_spawn_egg","localizedName":"Villager Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:vindicator_spawn_egg","unlocalizedName":"item.minecraft.vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:vine","unlocalizedName":"block.minecraft.vine","localizedName":"Vines","maxStackSize":64,"maxDamage":0},{"id":"minecraft:wandering_trader_spawn_egg","unlocalizedName":"item.minecraft.wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:water_bucket","unlocalizedName":"item.minecraft.water_bucket","localizedName":"Water Bucket","maxStackSize":1,"maxDamage":0},{"id":"minecraft:wet_sponge","unlocalizedName":"block.minecraft.wet_sponge","localizedName":"Wet Sponge","maxStackSize":64,"maxDamage":0},{"id":"minecraft:wheat","unlocalizedName":"item.minecraft.wheat","localizedName":"Wheat","maxStackSize":64,"maxDamage":0},{"id":"minecraft:wheat_seeds","unlocalizedName":"item.minecraft.wheat_seeds","localizedName":"Wheat Seeds","maxStackSize":64,"maxDamage":0},{"id":"minecraft:white_banner","unlocalizedName":"block.minecraft.white_banner","localizedName":"White Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:white_bed","unlocalizedName":"block.minecraft.white_bed","localizedName":"White Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:white_carpet","unlocalizedName":"block.minecraft.white_carpet","localizedName":"White Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:white_concrete","unlocalizedName":"block.minecraft.white_concrete","localizedName":"White Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:white_concrete_powder","unlocalizedName":"block.minecraft.white_concrete_powder","localizedName":"White Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:white_dye","unlocalizedName":"item.minecraft.white_dye","localizedName":"White Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:white_glazed_terracotta","unlocalizedName":"block.minecraft.white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:white_shulker_box","unlocalizedName":"block.minecraft.white_shulker_box","localizedName":"White Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:white_stained_glass","unlocalizedName":"block.minecraft.white_stained_glass","localizedName":"White Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:white_stained_glass_pane","unlocalizedName":"block.minecraft.white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:white_terracotta","unlocalizedName":"block.minecraft.white_terracotta","localizedName":"White Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:white_tulip","unlocalizedName":"block.minecraft.white_tulip","localizedName":"White Tulip","maxStackSize":64,"maxDamage":0},{"id":"minecraft:white_wool","unlocalizedName":"block.minecraft.white_wool","localizedName":"White Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:witch_spawn_egg","unlocalizedName":"item.minecraft.witch_spawn_egg","localizedName":"Witch Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:wither_rose","unlocalizedName":"block.minecraft.wither_rose","localizedName":"Wither Rose","maxStackSize":64,"maxDamage":0},{"id":"minecraft:wither_skeleton_skull","unlocalizedName":"block.minecraft.wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxStackSize":64,"maxDamage":0},{"id":"minecraft:wither_skeleton_spawn_egg","unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:wolf_spawn_egg","unlocalizedName":"item.minecraft.wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:wooden_axe","unlocalizedName":"item.minecraft.wooden_axe","localizedName":"Wooden Axe","maxStackSize":1,"maxDamage":59},{"id":"minecraft:wooden_hoe","unlocalizedName":"item.minecraft.wooden_hoe","localizedName":"Wooden Hoe","maxStackSize":1,"maxDamage":59},{"id":"minecraft:wooden_pickaxe","unlocalizedName":"item.minecraft.wooden_pickaxe","localizedName":"Wooden Pickaxe","maxStackSize":1,"maxDamage":59},{"id":"minecraft:wooden_shovel","unlocalizedName":"item.minecraft.wooden_shovel","localizedName":"Wooden Shovel","maxStackSize":1,"maxDamage":59},{"id":"minecraft:wooden_sword","unlocalizedName":"item.minecraft.wooden_sword","localizedName":"Wooden Sword","maxStackSize":1,"maxDamage":59},{"id":"minecraft:writable_book","unlocalizedName":"item.minecraft.writable_book","localizedName":"Book and Quill","maxStackSize":1,"maxDamage":0},{"id":"minecraft:written_book","unlocalizedName":"item.minecraft.written_book","localizedName":"Written Book","maxStackSize":16,"maxDamage":0},{"id":"minecraft:yellow_banner","unlocalizedName":"block.minecraft.yellow_banner","localizedName":"Yellow Banner","maxStackSize":16,"maxDamage":0},{"id":"minecraft:yellow_bed","unlocalizedName":"block.minecraft.yellow_bed","localizedName":"Yellow Bed","maxStackSize":1,"maxDamage":0},{"id":"minecraft:yellow_carpet","unlocalizedName":"block.minecraft.yellow_carpet","localizedName":"Yellow Carpet","maxStackSize":64,"maxDamage":0},{"id":"minecraft:yellow_concrete","unlocalizedName":"block.minecraft.yellow_concrete","localizedName":"Yellow Concrete","maxStackSize":64,"maxDamage":0},{"id":"minecraft:yellow_concrete_powder","unlocalizedName":"block.minecraft.yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxStackSize":64,"maxDamage":0},{"id":"minecraft:yellow_dye","unlocalizedName":"item.minecraft.yellow_dye","localizedName":"Yellow Dye","maxStackSize":64,"maxDamage":0},{"id":"minecraft:yellow_glazed_terracotta","unlocalizedName":"block.minecraft.yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:yellow_shulker_box","unlocalizedName":"block.minecraft.yellow_shulker_box","localizedName":"Yellow Shulker Box","maxStackSize":1,"maxDamage":0},{"id":"minecraft:yellow_stained_glass","unlocalizedName":"block.minecraft.yellow_stained_glass","localizedName":"Yellow Stained Glass","maxStackSize":64,"maxDamage":0},{"id":"minecraft:yellow_stained_glass_pane","unlocalizedName":"block.minecraft.yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxStackSize":64,"maxDamage":0},{"id":"minecraft:yellow_terracotta","unlocalizedName":"block.minecraft.yellow_terracotta","localizedName":"Yellow Terracotta","maxStackSize":64,"maxDamage":0},{"id":"minecraft:yellow_wool","unlocalizedName":"block.minecraft.yellow_wool","localizedName":"Yellow Wool","maxStackSize":64,"maxDamage":0},{"id":"minecraft:zombie_head","unlocalizedName":"block.minecraft.zombie_head","localizedName":"Zombie Head","maxStackSize":64,"maxDamage":0},{"id":"minecraft:zombie_horse_spawn_egg","unlocalizedName":"item.minecraft.zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:zombie_pigman_spawn_egg","unlocalizedName":"item.minecraft.zombie_pigman_spawn_egg","localizedName":"Zombie Pigman Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:zombie_spawn_egg","unlocalizedName":"item.minecraft.zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxStackSize":64,"maxDamage":0},{"id":"minecraft:zombie_villager_spawn_egg","unlocalizedName":"item.minecraft.zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxStackSize":64,"maxDamage":0}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/items.115.json b/src/main/resources/com/sk89q/worldedit/world/registry/items.115.json new file mode 100644 index 0000000..1e7f6a3 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/items.115.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_boat","unlocalizedName":"item.minecraft.acacia_boat","localizedName":"Acacia Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:acacia_button","unlocalizedName":"block.minecraft.acacia_button","localizedName":"Acacia Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_door","unlocalizedName":"block.minecraft.acacia_door","localizedName":"Acacia Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_fence","unlocalizedName":"block.minecraft.acacia_fence","localizedName":"Acacia Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_fence_gate","unlocalizedName":"block.minecraft.acacia_fence_gate","localizedName":"Acacia Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_leaves","unlocalizedName":"block.minecraft.acacia_leaves","localizedName":"Acacia Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_log","unlocalizedName":"block.minecraft.acacia_log","localizedName":"Acacia Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_planks","unlocalizedName":"block.minecraft.acacia_planks","localizedName":"Acacia Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_pressure_plate","unlocalizedName":"block.minecraft.acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_sapling","unlocalizedName":"block.minecraft.acacia_sapling","localizedName":"Acacia Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_sign","unlocalizedName":"block.minecraft.acacia_sign","localizedName":"Acacia Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:acacia_slab","unlocalizedName":"block.minecraft.acacia_slab","localizedName":"Acacia Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_stairs","unlocalizedName":"block.minecraft.acacia_stairs","localizedName":"Acacia Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_trapdoor","unlocalizedName":"block.minecraft.acacia_trapdoor","localizedName":"Acacia Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_wood","unlocalizedName":"block.minecraft.acacia_wood","localizedName":"Acacia Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:activator_rail","unlocalizedName":"block.minecraft.activator_rail","localizedName":"Activator Rail","maxDamage":0,"maxStackSize":64},{"id":"minecraft:air","unlocalizedName":"block.minecraft.air","localizedName":"Air","maxDamage":0,"maxStackSize":64},{"id":"minecraft:allium","unlocalizedName":"block.minecraft.allium","localizedName":"Allium","maxDamage":0,"maxStackSize":64},{"id":"minecraft:andesite","unlocalizedName":"block.minecraft.andesite","localizedName":"Andesite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:andesite_slab","unlocalizedName":"block.minecraft.andesite_slab","localizedName":"Andesite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:andesite_stairs","unlocalizedName":"block.minecraft.andesite_stairs","localizedName":"Andesite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:andesite_wall","unlocalizedName":"block.minecraft.andesite_wall","localizedName":"Andesite Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:anvil","unlocalizedName":"block.minecraft.anvil","localizedName":"Anvil","maxDamage":0,"maxStackSize":64},{"id":"minecraft:apple","unlocalizedName":"item.minecraft.apple","localizedName":"Apple","maxDamage":0,"maxStackSize":64},{"id":"minecraft:armor_stand","unlocalizedName":"item.minecraft.armor_stand","localizedName":"Armor Stand","maxDamage":0,"maxStackSize":16},{"id":"minecraft:arrow","unlocalizedName":"item.minecraft.arrow","localizedName":"Arrow","maxDamage":0,"maxStackSize":64},{"id":"minecraft:azure_bluet","unlocalizedName":"block.minecraft.azure_bluet","localizedName":"Azure Bluet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:baked_potato","unlocalizedName":"item.minecraft.baked_potato","localizedName":"Baked Potato","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bamboo","unlocalizedName":"block.minecraft.bamboo","localizedName":"Bamboo","maxDamage":0,"maxStackSize":64},{"id":"minecraft:barrel","unlocalizedName":"block.minecraft.barrel","localizedName":"Barrel","maxDamage":0,"maxStackSize":64},{"id":"minecraft:barrier","unlocalizedName":"block.minecraft.barrier","localizedName":"Barrier","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bat_spawn_egg","unlocalizedName":"item.minecraft.bat_spawn_egg","localizedName":"Bat Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beacon","unlocalizedName":"block.minecraft.beacon","localizedName":"Beacon","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bedrock","unlocalizedName":"block.minecraft.bedrock","localizedName":"Bedrock","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bee_nest","unlocalizedName":"block.minecraft.bee_nest","localizedName":"Bee Nest","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bee_spawn_egg","unlocalizedName":"item.minecraft.bee_spawn_egg","localizedName":"Bee Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beef","unlocalizedName":"item.minecraft.beef","localizedName":"Raw Beef","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beehive","unlocalizedName":"block.minecraft.beehive","localizedName":"Beehive","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beetroot","unlocalizedName":"item.minecraft.beetroot","localizedName":"Beetroot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beetroot_seeds","unlocalizedName":"item.minecraft.beetroot_seeds","localizedName":"Beetroot Seeds","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beetroot_soup","unlocalizedName":"item.minecraft.beetroot_soup","localizedName":"Beetroot Soup","maxDamage":0,"maxStackSize":1},{"id":"minecraft:bell","unlocalizedName":"block.minecraft.bell","localizedName":"Bell","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_boat","unlocalizedName":"item.minecraft.birch_boat","localizedName":"Birch Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:birch_button","unlocalizedName":"block.minecraft.birch_button","localizedName":"Birch Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_door","unlocalizedName":"block.minecraft.birch_door","localizedName":"Birch Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_fence","unlocalizedName":"block.minecraft.birch_fence","localizedName":"Birch Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_fence_gate","unlocalizedName":"block.minecraft.birch_fence_gate","localizedName":"Birch Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_leaves","unlocalizedName":"block.minecraft.birch_leaves","localizedName":"Birch Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_log","unlocalizedName":"block.minecraft.birch_log","localizedName":"Birch Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_planks","unlocalizedName":"block.minecraft.birch_planks","localizedName":"Birch Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_pressure_plate","unlocalizedName":"block.minecraft.birch_pressure_plate","localizedName":"Birch Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_sapling","unlocalizedName":"block.minecraft.birch_sapling","localizedName":"Birch Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_sign","unlocalizedName":"block.minecraft.birch_sign","localizedName":"Birch Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:birch_slab","unlocalizedName":"block.minecraft.birch_slab","localizedName":"Birch Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_stairs","unlocalizedName":"block.minecraft.birch_stairs","localizedName":"Birch Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_trapdoor","unlocalizedName":"block.minecraft.birch_trapdoor","localizedName":"Birch Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_wood","unlocalizedName":"block.minecraft.birch_wood","localizedName":"Birch Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_banner","unlocalizedName":"block.minecraft.black_banner","localizedName":"Black Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:black_bed","unlocalizedName":"block.minecraft.black_bed","localizedName":"Black Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:black_carpet","unlocalizedName":"block.minecraft.black_carpet","localizedName":"Black Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_concrete","unlocalizedName":"block.minecraft.black_concrete","localizedName":"Black Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_concrete_powder","unlocalizedName":"block.minecraft.black_concrete_powder","localizedName":"Black Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_dye","unlocalizedName":"item.minecraft.black_dye","localizedName":"Black Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_glazed_terracotta","unlocalizedName":"block.minecraft.black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_shulker_box","unlocalizedName":"block.minecraft.black_shulker_box","localizedName":"Black Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:black_stained_glass","unlocalizedName":"block.minecraft.black_stained_glass","localizedName":"Black Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_stained_glass_pane","unlocalizedName":"block.minecraft.black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_terracotta","unlocalizedName":"block.minecraft.black_terracotta","localizedName":"Black Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_wool","unlocalizedName":"block.minecraft.black_wool","localizedName":"Black Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blast_furnace","unlocalizedName":"block.minecraft.blast_furnace","localizedName":"Blast Furnace","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blaze_powder","unlocalizedName":"item.minecraft.blaze_powder","localizedName":"Blaze Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blaze_rod","unlocalizedName":"item.minecraft.blaze_rod","localizedName":"Blaze Rod","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blaze_spawn_egg","unlocalizedName":"item.minecraft.blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_banner","unlocalizedName":"block.minecraft.blue_banner","localizedName":"Blue Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:blue_bed","unlocalizedName":"block.minecraft.blue_bed","localizedName":"Blue Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:blue_carpet","unlocalizedName":"block.minecraft.blue_carpet","localizedName":"Blue Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_concrete","unlocalizedName":"block.minecraft.blue_concrete","localizedName":"Blue Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_concrete_powder","unlocalizedName":"block.minecraft.blue_concrete_powder","localizedName":"Blue Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_dye","unlocalizedName":"item.minecraft.blue_dye","localizedName":"Blue Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_glazed_terracotta","unlocalizedName":"block.minecraft.blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_ice","unlocalizedName":"block.minecraft.blue_ice","localizedName":"Blue Ice","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_orchid","unlocalizedName":"block.minecraft.blue_orchid","localizedName":"Blue Orchid","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_shulker_box","unlocalizedName":"block.minecraft.blue_shulker_box","localizedName":"Blue Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:blue_stained_glass","unlocalizedName":"block.minecraft.blue_stained_glass","localizedName":"Blue Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_stained_glass_pane","unlocalizedName":"block.minecraft.blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_terracotta","unlocalizedName":"block.minecraft.blue_terracotta","localizedName":"Blue Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_wool","unlocalizedName":"block.minecraft.blue_wool","localizedName":"Blue Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bone","unlocalizedName":"item.minecraft.bone","localizedName":"Bone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bone_block","unlocalizedName":"block.minecraft.bone_block","localizedName":"Bone Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bone_meal","unlocalizedName":"item.minecraft.bone_meal","localizedName":"Bone Meal","maxDamage":0,"maxStackSize":64},{"id":"minecraft:book","unlocalizedName":"item.minecraft.book","localizedName":"Book","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bookshelf","unlocalizedName":"block.minecraft.bookshelf","localizedName":"Bookshelf","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bow","unlocalizedName":"item.minecraft.bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1},{"id":"minecraft:bowl","unlocalizedName":"item.minecraft.bowl","localizedName":"Bowl","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brain_coral","unlocalizedName":"block.minecraft.brain_coral","localizedName":"Brain Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brain_coral_block","unlocalizedName":"block.minecraft.brain_coral_block","localizedName":"Brain Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brain_coral_fan","unlocalizedName":"block.minecraft.brain_coral_fan","localizedName":"Brain Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bread","unlocalizedName":"item.minecraft.bread","localizedName":"Bread","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brewing_stand","unlocalizedName":"block.minecraft.brewing_stand","localizedName":"Brewing Stand","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brick","unlocalizedName":"item.minecraft.brick","localizedName":"Brick","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brick_slab","unlocalizedName":"block.minecraft.brick_slab","localizedName":"Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brick_stairs","unlocalizedName":"block.minecraft.brick_stairs","localizedName":"Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brick_wall","unlocalizedName":"block.minecraft.brick_wall","localizedName":"Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bricks","unlocalizedName":"block.minecraft.bricks","localizedName":"Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_banner","unlocalizedName":"block.minecraft.brown_banner","localizedName":"Brown Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:brown_bed","unlocalizedName":"block.minecraft.brown_bed","localizedName":"Brown Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:brown_carpet","unlocalizedName":"block.minecraft.brown_carpet","localizedName":"Brown Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_concrete","unlocalizedName":"block.minecraft.brown_concrete","localizedName":"Brown Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_concrete_powder","unlocalizedName":"block.minecraft.brown_concrete_powder","localizedName":"Brown Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_dye","unlocalizedName":"item.minecraft.brown_dye","localizedName":"Brown Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_glazed_terracotta","unlocalizedName":"block.minecraft.brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_mushroom","unlocalizedName":"block.minecraft.brown_mushroom","localizedName":"Brown Mushroom","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_mushroom_block","unlocalizedName":"block.minecraft.brown_mushroom_block","localizedName":"Brown Mushroom Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_shulker_box","unlocalizedName":"block.minecraft.brown_shulker_box","localizedName":"Brown Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:brown_stained_glass","unlocalizedName":"block.minecraft.brown_stained_glass","localizedName":"Brown Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_stained_glass_pane","unlocalizedName":"block.minecraft.brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_terracotta","unlocalizedName":"block.minecraft.brown_terracotta","localizedName":"Brown Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_wool","unlocalizedName":"block.minecraft.brown_wool","localizedName":"Brown Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bubble_coral","unlocalizedName":"block.minecraft.bubble_coral","localizedName":"Bubble Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bubble_coral_block","unlocalizedName":"block.minecraft.bubble_coral_block","localizedName":"Bubble Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bubble_coral_fan","unlocalizedName":"block.minecraft.bubble_coral_fan","localizedName":"Bubble Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bucket","unlocalizedName":"item.minecraft.bucket","localizedName":"Bucket","maxDamage":0,"maxStackSize":16},{"id":"minecraft:cactus","unlocalizedName":"block.minecraft.cactus","localizedName":"Cactus","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cake","unlocalizedName":"block.minecraft.cake","localizedName":"Cake","maxDamage":0,"maxStackSize":1},{"id":"minecraft:campfire","unlocalizedName":"block.minecraft.campfire","localizedName":"Campfire","maxDamage":0,"maxStackSize":64},{"id":"minecraft:carrot","unlocalizedName":"item.minecraft.carrot","localizedName":"Carrot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:carrot_on_a_stick","unlocalizedName":"item.minecraft.carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1},{"id":"minecraft:cartography_table","unlocalizedName":"block.minecraft.cartography_table","localizedName":"Cartography Table","maxDamage":0,"maxStackSize":64},{"id":"minecraft:carved_pumpkin","unlocalizedName":"block.minecraft.carved_pumpkin","localizedName":"Carved Pumpkin","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cat_spawn_egg","unlocalizedName":"item.minecraft.cat_spawn_egg","localizedName":"Cat Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cauldron","unlocalizedName":"block.minecraft.cauldron","localizedName":"Cauldron","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cave_spider_spawn_egg","unlocalizedName":"item.minecraft.cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chain_command_block","unlocalizedName":"block.minecraft.chain_command_block","localizedName":"Chain Command Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chainmail_boots","unlocalizedName":"item.minecraft.chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1},{"id":"minecraft:chainmail_chestplate","unlocalizedName":"item.minecraft.chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1},{"id":"minecraft:chainmail_helmet","unlocalizedName":"item.minecraft.chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1},{"id":"minecraft:chainmail_leggings","unlocalizedName":"item.minecraft.chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1},{"id":"minecraft:charcoal","unlocalizedName":"item.minecraft.charcoal","localizedName":"Charcoal","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chest","unlocalizedName":"block.minecraft.chest","localizedName":"Chest","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chest_minecart","unlocalizedName":"item.minecraft.chest_minecart","localizedName":"Minecart with Chest","maxDamage":0,"maxStackSize":1},{"id":"minecraft:chicken","unlocalizedName":"item.minecraft.chicken","localizedName":"Raw Chicken","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chicken_spawn_egg","unlocalizedName":"item.minecraft.chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chipped_anvil","unlocalizedName":"block.minecraft.chipped_anvil","localizedName":"Chipped Anvil","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chiseled_quartz_block","unlocalizedName":"block.minecraft.chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chiseled_red_sandstone","unlocalizedName":"block.minecraft.chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chiseled_sandstone","unlocalizedName":"block.minecraft.chiseled_sandstone","localizedName":"Chiseled Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chiseled_stone_bricks","unlocalizedName":"block.minecraft.chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chorus_flower","unlocalizedName":"block.minecraft.chorus_flower","localizedName":"Chorus Flower","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chorus_fruit","unlocalizedName":"item.minecraft.chorus_fruit","localizedName":"Chorus Fruit","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chorus_plant","unlocalizedName":"block.minecraft.chorus_plant","localizedName":"Chorus Plant","maxDamage":0,"maxStackSize":64},{"id":"minecraft:clay","unlocalizedName":"block.minecraft.clay","localizedName":"Clay","maxDamage":0,"maxStackSize":64},{"id":"minecraft:clay_ball","unlocalizedName":"item.minecraft.clay_ball","localizedName":"Clay","maxDamage":0,"maxStackSize":64},{"id":"minecraft:clock","unlocalizedName":"item.minecraft.clock","localizedName":"Clock","maxDamage":0,"maxStackSize":64},{"id":"minecraft:coal","unlocalizedName":"item.minecraft.coal","localizedName":"Coal","maxDamage":0,"maxStackSize":64},{"id":"minecraft:coal_block","unlocalizedName":"block.minecraft.coal_block","localizedName":"Block of Coal","maxDamage":0,"maxStackSize":64},{"id":"minecraft:coal_ore","unlocalizedName":"block.minecraft.coal_ore","localizedName":"Coal Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:coarse_dirt","unlocalizedName":"block.minecraft.coarse_dirt","localizedName":"Coarse Dirt","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cobblestone","unlocalizedName":"block.minecraft.cobblestone","localizedName":"Cobblestone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cobblestone_slab","unlocalizedName":"block.minecraft.cobblestone_slab","localizedName":"Cobblestone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cobblestone_stairs","unlocalizedName":"block.minecraft.cobblestone_stairs","localizedName":"Cobblestone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cobblestone_wall","unlocalizedName":"block.minecraft.cobblestone_wall","localizedName":"Cobblestone Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cobweb","unlocalizedName":"block.minecraft.cobweb","localizedName":"Cobweb","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cocoa_beans","unlocalizedName":"item.minecraft.cocoa_beans","localizedName":"Cocoa Beans","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cod","unlocalizedName":"item.minecraft.cod","localizedName":"Raw Cod","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cod_bucket","unlocalizedName":"item.minecraft.cod_bucket","localizedName":"Bucket of Cod","maxDamage":0,"maxStackSize":1},{"id":"minecraft:cod_spawn_egg","unlocalizedName":"item.minecraft.cod_spawn_egg","localizedName":"Cod Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:command_block","unlocalizedName":"block.minecraft.command_block","localizedName":"Command Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:command_block_minecart","unlocalizedName":"item.minecraft.command_block_minecart","localizedName":"Minecart with Command Block","maxDamage":0,"maxStackSize":1},{"id":"minecraft:comparator","unlocalizedName":"block.minecraft.comparator","localizedName":"Redstone Comparator","maxDamage":0,"maxStackSize":64},{"id":"minecraft:compass","unlocalizedName":"item.minecraft.compass","localizedName":"Compass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:composter","unlocalizedName":"block.minecraft.composter","localizedName":"Composter","maxDamage":0,"maxStackSize":64},{"id":"minecraft:conduit","unlocalizedName":"block.minecraft.conduit","localizedName":"Conduit","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_beef","unlocalizedName":"item.minecraft.cooked_beef","localizedName":"Steak","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_chicken","unlocalizedName":"item.minecraft.cooked_chicken","localizedName":"Cooked Chicken","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_cod","unlocalizedName":"item.minecraft.cooked_cod","localizedName":"Cooked Cod","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_mutton","unlocalizedName":"item.minecraft.cooked_mutton","localizedName":"Cooked Mutton","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_porkchop","unlocalizedName":"item.minecraft.cooked_porkchop","localizedName":"Cooked Porkchop","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_rabbit","unlocalizedName":"item.minecraft.cooked_rabbit","localizedName":"Cooked Rabbit","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_salmon","unlocalizedName":"item.minecraft.cooked_salmon","localizedName":"Cooked Salmon","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cookie","unlocalizedName":"item.minecraft.cookie","localizedName":"Cookie","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cornflower","unlocalizedName":"block.minecraft.cornflower","localizedName":"Cornflower","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cow_spawn_egg","unlocalizedName":"item.minecraft.cow_spawn_egg","localizedName":"Cow Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cracked_stone_bricks","unlocalizedName":"block.minecraft.cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:crafting_table","unlocalizedName":"block.minecraft.crafting_table","localizedName":"Crafting Table","maxDamage":0,"maxStackSize":64},{"id":"minecraft:creeper_banner_pattern","unlocalizedName":"item.minecraft.creeper_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1},{"id":"minecraft:creeper_head","unlocalizedName":"block.minecraft.creeper_head","localizedName":"Creeper Head","maxDamage":0,"maxStackSize":64},{"id":"minecraft:creeper_spawn_egg","unlocalizedName":"item.minecraft.creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:crossbow","unlocalizedName":"item.minecraft.crossbow","localizedName":"Crossbow","maxDamage":326,"maxStackSize":1},{"id":"minecraft:cut_red_sandstone","unlocalizedName":"block.minecraft.cut_red_sandstone","localizedName":"Cut Red Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cut_red_sandstone_slab","unlocalizedName":"block.minecraft.cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cut_sandstone","unlocalizedName":"block.minecraft.cut_sandstone","localizedName":"Cut Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cut_sandstone_slab","unlocalizedName":"block.minecraft.cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_banner","unlocalizedName":"block.minecraft.cyan_banner","localizedName":"Cyan Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:cyan_bed","unlocalizedName":"block.minecraft.cyan_bed","localizedName":"Cyan Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:cyan_carpet","unlocalizedName":"block.minecraft.cyan_carpet","localizedName":"Cyan Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_concrete","unlocalizedName":"block.minecraft.cyan_concrete","localizedName":"Cyan Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_concrete_powder","unlocalizedName":"block.minecraft.cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_dye","unlocalizedName":"item.minecraft.cyan_dye","localizedName":"Cyan Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_glazed_terracotta","unlocalizedName":"block.minecraft.cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_shulker_box","unlocalizedName":"block.minecraft.cyan_shulker_box","localizedName":"Cyan Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:cyan_stained_glass","unlocalizedName":"block.minecraft.cyan_stained_glass","localizedName":"Cyan Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_stained_glass_pane","unlocalizedName":"block.minecraft.cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_terracotta","unlocalizedName":"block.minecraft.cyan_terracotta","localizedName":"Cyan Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_wool","unlocalizedName":"block.minecraft.cyan_wool","localizedName":"Cyan Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:damaged_anvil","unlocalizedName":"block.minecraft.damaged_anvil","localizedName":"Damaged Anvil","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dandelion","unlocalizedName":"block.minecraft.dandelion","localizedName":"Dandelion","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_boat","unlocalizedName":"item.minecraft.dark_oak_boat","localizedName":"Dark Oak Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:dark_oak_button","unlocalizedName":"block.minecraft.dark_oak_button","localizedName":"Dark Oak Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_door","unlocalizedName":"block.minecraft.dark_oak_door","localizedName":"Dark Oak Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_fence","unlocalizedName":"block.minecraft.dark_oak_fence","localizedName":"Dark Oak Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_fence_gate","unlocalizedName":"block.minecraft.dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_leaves","unlocalizedName":"block.minecraft.dark_oak_leaves","localizedName":"Dark Oak Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_log","unlocalizedName":"block.minecraft.dark_oak_log","localizedName":"Dark Oak Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_planks","unlocalizedName":"block.minecraft.dark_oak_planks","localizedName":"Dark Oak Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_pressure_plate","unlocalizedName":"block.minecraft.dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_sapling","unlocalizedName":"block.minecraft.dark_oak_sapling","localizedName":"Dark Oak Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_sign","unlocalizedName":"block.minecraft.dark_oak_sign","localizedName":"Dark Oak Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:dark_oak_slab","unlocalizedName":"block.minecraft.dark_oak_slab","localizedName":"Dark Oak Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_stairs","unlocalizedName":"block.minecraft.dark_oak_stairs","localizedName":"Dark Oak Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_trapdoor","unlocalizedName":"block.minecraft.dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_wood","unlocalizedName":"block.minecraft.dark_oak_wood","localizedName":"Dark Oak Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_prismarine","unlocalizedName":"block.minecraft.dark_prismarine","localizedName":"Dark Prismarine","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_prismarine_slab","unlocalizedName":"block.minecraft.dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_prismarine_stairs","unlocalizedName":"block.minecraft.dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:daylight_detector","unlocalizedName":"block.minecraft.daylight_detector","localizedName":"Daylight Detector","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_brain_coral","unlocalizedName":"block.minecraft.dead_brain_coral","localizedName":"Dead Brain Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_brain_coral_block","unlocalizedName":"block.minecraft.dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_brain_coral_fan","unlocalizedName":"block.minecraft.dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_bubble_coral","unlocalizedName":"block.minecraft.dead_bubble_coral","localizedName":"Dead Bubble Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_bubble_coral_block","unlocalizedName":"block.minecraft.dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_bubble_coral_fan","unlocalizedName":"block.minecraft.dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_bush","unlocalizedName":"block.minecraft.dead_bush","localizedName":"Dead Bush","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_fire_coral","unlocalizedName":"block.minecraft.dead_fire_coral","localizedName":"Dead Fire Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_fire_coral_block","unlocalizedName":"block.minecraft.dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_fire_coral_fan","unlocalizedName":"block.minecraft.dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_horn_coral","unlocalizedName":"block.minecraft.dead_horn_coral","localizedName":"Dead Horn Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_horn_coral_block","unlocalizedName":"block.minecraft.dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_horn_coral_fan","unlocalizedName":"block.minecraft.dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_tube_coral","unlocalizedName":"block.minecraft.dead_tube_coral","localizedName":"Dead Tube Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_tube_coral_block","unlocalizedName":"block.minecraft.dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_tube_coral_fan","unlocalizedName":"block.minecraft.dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:debug_stick","unlocalizedName":"item.minecraft.debug_stick","localizedName":"Debug Stick","maxDamage":0,"maxStackSize":1},{"id":"minecraft:detector_rail","unlocalizedName":"block.minecraft.detector_rail","localizedName":"Detector Rail","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diamond","unlocalizedName":"item.minecraft.diamond","localizedName":"Diamond","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diamond_axe","unlocalizedName":"item.minecraft.diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1},{"id":"minecraft:diamond_block","unlocalizedName":"block.minecraft.diamond_block","localizedName":"Block of Diamond","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diamond_boots","unlocalizedName":"item.minecraft.diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1},{"id":"minecraft:diamond_chestplate","unlocalizedName":"item.minecraft.diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1},{"id":"minecraft:diamond_helmet","unlocalizedName":"item.minecraft.diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1},{"id":"minecraft:diamond_hoe","unlocalizedName":"item.minecraft.diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1},{"id":"minecraft:diamond_horse_armor","unlocalizedName":"item.minecraft.diamond_horse_armor","localizedName":"Diamond Horse Armor","maxDamage":0,"maxStackSize":1},{"id":"minecraft:diamond_leggings","unlocalizedName":"item.minecraft.diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1},{"id":"minecraft:diamond_ore","unlocalizedName":"block.minecraft.diamond_ore","localizedName":"Diamond Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diamond_pickaxe","unlocalizedName":"item.minecraft.diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1},{"id":"minecraft:diamond_shovel","unlocalizedName":"item.minecraft.diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1},{"id":"minecraft:diamond_sword","unlocalizedName":"item.minecraft.diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1},{"id":"minecraft:diorite","unlocalizedName":"block.minecraft.diorite","localizedName":"Diorite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diorite_slab","unlocalizedName":"block.minecraft.diorite_slab","localizedName":"Diorite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diorite_stairs","unlocalizedName":"block.minecraft.diorite_stairs","localizedName":"Diorite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diorite_wall","unlocalizedName":"block.minecraft.diorite_wall","localizedName":"Diorite Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dirt","unlocalizedName":"block.minecraft.dirt","localizedName":"Dirt","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dispenser","unlocalizedName":"block.minecraft.dispenser","localizedName":"Dispenser","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dolphin_spawn_egg","unlocalizedName":"item.minecraft.dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:donkey_spawn_egg","unlocalizedName":"item.minecraft.donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dragon_breath","unlocalizedName":"item.minecraft.dragon_breath","localizedName":"Dragon's Breath","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dragon_egg","unlocalizedName":"block.minecraft.dragon_egg","localizedName":"Dragon Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dragon_head","unlocalizedName":"block.minecraft.dragon_head","localizedName":"Dragon Head","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dried_kelp","unlocalizedName":"item.minecraft.dried_kelp","localizedName":"Dried Kelp","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dried_kelp_block","unlocalizedName":"block.minecraft.dried_kelp_block","localizedName":"Dried Kelp Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dropper","unlocalizedName":"block.minecraft.dropper","localizedName":"Dropper","maxDamage":0,"maxStackSize":64},{"id":"minecraft:drowned_spawn_egg","unlocalizedName":"item.minecraft.drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:egg","unlocalizedName":"item.minecraft.egg","localizedName":"Egg","maxDamage":0,"maxStackSize":16},{"id":"minecraft:elder_guardian_spawn_egg","unlocalizedName":"item.minecraft.elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:elytra","unlocalizedName":"item.minecraft.elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1},{"id":"minecraft:emerald","unlocalizedName":"item.minecraft.emerald","localizedName":"Emerald","maxDamage":0,"maxStackSize":64},{"id":"minecraft:emerald_block","unlocalizedName":"block.minecraft.emerald_block","localizedName":"Block of Emerald","maxDamage":0,"maxStackSize":64},{"id":"minecraft:emerald_ore","unlocalizedName":"block.minecraft.emerald_ore","localizedName":"Emerald Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:enchanted_book","unlocalizedName":"item.minecraft.enchanted_book","localizedName":"Enchanted Book","maxDamage":0,"maxStackSize":1},{"id":"minecraft:enchanted_golden_apple","unlocalizedName":"item.minecraft.enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxDamage":0,"maxStackSize":64},{"id":"minecraft:enchanting_table","unlocalizedName":"block.minecraft.enchanting_table","localizedName":"Enchanting Table","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_crystal","unlocalizedName":"item.minecraft.end_crystal","localizedName":"End Crystal","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_portal_frame","unlocalizedName":"block.minecraft.end_portal_frame","localizedName":"End Portal Frame","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_rod","unlocalizedName":"block.minecraft.end_rod","localizedName":"End Rod","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_stone","unlocalizedName":"block.minecraft.end_stone","localizedName":"End Stone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_stone_brick_slab","unlocalizedName":"block.minecraft.end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_stone_brick_stairs","unlocalizedName":"block.minecraft.end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_stone_brick_wall","unlocalizedName":"block.minecraft.end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_stone_bricks","unlocalizedName":"block.minecraft.end_stone_bricks","localizedName":"End Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ender_chest","unlocalizedName":"block.minecraft.ender_chest","localizedName":"Ender Chest","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ender_eye","unlocalizedName":"item.minecraft.ender_eye","localizedName":"Eye of Ender","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ender_pearl","unlocalizedName":"item.minecraft.ender_pearl","localizedName":"Ender Pearl","maxDamage":0,"maxStackSize":16},{"id":"minecraft:enderman_spawn_egg","unlocalizedName":"item.minecraft.enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:endermite_spawn_egg","unlocalizedName":"item.minecraft.endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:evoker_spawn_egg","unlocalizedName":"item.minecraft.evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:experience_bottle","unlocalizedName":"item.minecraft.experience_bottle","localizedName":"Bottle o' Enchanting","maxDamage":0,"maxStackSize":64},{"id":"minecraft:farmland","unlocalizedName":"block.minecraft.farmland","localizedName":"Farmland","maxDamage":0,"maxStackSize":64},{"id":"minecraft:feather","unlocalizedName":"item.minecraft.feather","localizedName":"Feather","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fermented_spider_eye","unlocalizedName":"item.minecraft.fermented_spider_eye","localizedName":"Fermented Spider Eye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fern","unlocalizedName":"block.minecraft.fern","localizedName":"Fern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:filled_map","unlocalizedName":"item.minecraft.filled_map","localizedName":"Map","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fire_charge","unlocalizedName":"item.minecraft.fire_charge","localizedName":"Fire Charge","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fire_coral","unlocalizedName":"block.minecraft.fire_coral","localizedName":"Fire Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fire_coral_block","unlocalizedName":"block.minecraft.fire_coral_block","localizedName":"Fire Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fire_coral_fan","unlocalizedName":"block.minecraft.fire_coral_fan","localizedName":"Fire Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:firework_rocket","unlocalizedName":"item.minecraft.firework_rocket","localizedName":"Firework Rocket","maxDamage":0,"maxStackSize":64},{"id":"minecraft:firework_star","unlocalizedName":"item.minecraft.firework_star","localizedName":"Firework Star","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fishing_rod","unlocalizedName":"item.minecraft.fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1},{"id":"minecraft:fletching_table","unlocalizedName":"block.minecraft.fletching_table","localizedName":"Fletching Table","maxDamage":0,"maxStackSize":64},{"id":"minecraft:flint","unlocalizedName":"item.minecraft.flint","localizedName":"Flint","maxDamage":0,"maxStackSize":64},{"id":"minecraft:flint_and_steel","unlocalizedName":"item.minecraft.flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1},{"id":"minecraft:flower_banner_pattern","unlocalizedName":"item.minecraft.flower_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1},{"id":"minecraft:flower_pot","unlocalizedName":"block.minecraft.flower_pot","localizedName":"Flower Pot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fox_spawn_egg","unlocalizedName":"item.minecraft.fox_spawn_egg","localizedName":"Fox Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:furnace","unlocalizedName":"block.minecraft.furnace","localizedName":"Furnace","maxDamage":0,"maxStackSize":64},{"id":"minecraft:furnace_minecart","unlocalizedName":"item.minecraft.furnace_minecart","localizedName":"Minecart with Furnace","maxDamage":0,"maxStackSize":1},{"id":"minecraft:ghast_spawn_egg","unlocalizedName":"item.minecraft.ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ghast_tear","unlocalizedName":"item.minecraft.ghast_tear","localizedName":"Ghast Tear","maxDamage":0,"maxStackSize":64},{"id":"minecraft:glass","unlocalizedName":"block.minecraft.glass","localizedName":"Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:glass_bottle","unlocalizedName":"item.minecraft.glass_bottle","localizedName":"Glass Bottle","maxDamage":0,"maxStackSize":64},{"id":"minecraft:glass_pane","unlocalizedName":"block.minecraft.glass_pane","localizedName":"Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:glistering_melon_slice","unlocalizedName":"item.minecraft.glistering_melon_slice","localizedName":"Glistering Melon Slice","maxDamage":0,"maxStackSize":64},{"id":"minecraft:globe_banner_pattern","unlocalizedName":"item.minecraft.globe_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1},{"id":"minecraft:glowstone","unlocalizedName":"block.minecraft.glowstone","localizedName":"Glowstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:glowstone_dust","unlocalizedName":"item.minecraft.glowstone_dust","localizedName":"Glowstone Dust","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gold_block","unlocalizedName":"block.minecraft.gold_block","localizedName":"Block of Gold","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gold_ingot","unlocalizedName":"item.minecraft.gold_ingot","localizedName":"Gold Ingot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gold_nugget","unlocalizedName":"item.minecraft.gold_nugget","localizedName":"Gold Nugget","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gold_ore","unlocalizedName":"block.minecraft.gold_ore","localizedName":"Gold Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:golden_apple","unlocalizedName":"item.minecraft.golden_apple","localizedName":"Golden Apple","maxDamage":0,"maxStackSize":64},{"id":"minecraft:golden_axe","unlocalizedName":"item.minecraft.golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1},{"id":"minecraft:golden_boots","unlocalizedName":"item.minecraft.golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1},{"id":"minecraft:golden_carrot","unlocalizedName":"item.minecraft.golden_carrot","localizedName":"Golden Carrot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:golden_chestplate","unlocalizedName":"item.minecraft.golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1},{"id":"minecraft:golden_helmet","unlocalizedName":"item.minecraft.golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1},{"id":"minecraft:golden_hoe","unlocalizedName":"item.minecraft.golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1},{"id":"minecraft:golden_horse_armor","unlocalizedName":"item.minecraft.golden_horse_armor","localizedName":"Golden Horse Armor","maxDamage":0,"maxStackSize":1},{"id":"minecraft:golden_leggings","unlocalizedName":"item.minecraft.golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1},{"id":"minecraft:golden_pickaxe","unlocalizedName":"item.minecraft.golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1},{"id":"minecraft:golden_shovel","unlocalizedName":"item.minecraft.golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1},{"id":"minecraft:golden_sword","unlocalizedName":"item.minecraft.golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1},{"id":"minecraft:granite","unlocalizedName":"block.minecraft.granite","localizedName":"Granite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:granite_slab","unlocalizedName":"block.minecraft.granite_slab","localizedName":"Granite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:granite_stairs","unlocalizedName":"block.minecraft.granite_stairs","localizedName":"Granite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:granite_wall","unlocalizedName":"block.minecraft.granite_wall","localizedName":"Granite Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:grass","unlocalizedName":"block.minecraft.grass","localizedName":"Grass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:grass_block","unlocalizedName":"block.minecraft.grass_block","localizedName":"Grass Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:grass_path","unlocalizedName":"block.minecraft.grass_path","localizedName":"Grass Path","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gravel","unlocalizedName":"block.minecraft.gravel","localizedName":"Gravel","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_banner","unlocalizedName":"block.minecraft.gray_banner","localizedName":"Gray Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:gray_bed","unlocalizedName":"block.minecraft.gray_bed","localizedName":"Gray Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:gray_carpet","unlocalizedName":"block.minecraft.gray_carpet","localizedName":"Gray Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_concrete","unlocalizedName":"block.minecraft.gray_concrete","localizedName":"Gray Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_concrete_powder","unlocalizedName":"block.minecraft.gray_concrete_powder","localizedName":"Gray Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_dye","unlocalizedName":"item.minecraft.gray_dye","localizedName":"Gray Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_glazed_terracotta","unlocalizedName":"block.minecraft.gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_shulker_box","unlocalizedName":"block.minecraft.gray_shulker_box","localizedName":"Gray Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:gray_stained_glass","unlocalizedName":"block.minecraft.gray_stained_glass","localizedName":"Gray Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_stained_glass_pane","unlocalizedName":"block.minecraft.gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_terracotta","unlocalizedName":"block.minecraft.gray_terracotta","localizedName":"Gray Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_wool","unlocalizedName":"block.minecraft.gray_wool","localizedName":"Gray Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_banner","unlocalizedName":"block.minecraft.green_banner","localizedName":"Green Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:green_bed","unlocalizedName":"block.minecraft.green_bed","localizedName":"Green Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:green_carpet","unlocalizedName":"block.minecraft.green_carpet","localizedName":"Green Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_concrete","unlocalizedName":"block.minecraft.green_concrete","localizedName":"Green Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_concrete_powder","unlocalizedName":"block.minecraft.green_concrete_powder","localizedName":"Green Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_dye","unlocalizedName":"item.minecraft.green_dye","localizedName":"Green Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_glazed_terracotta","unlocalizedName":"block.minecraft.green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_shulker_box","unlocalizedName":"block.minecraft.green_shulker_box","localizedName":"Green Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:green_stained_glass","unlocalizedName":"block.minecraft.green_stained_glass","localizedName":"Green Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_stained_glass_pane","unlocalizedName":"block.minecraft.green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_terracotta","unlocalizedName":"block.minecraft.green_terracotta","localizedName":"Green Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_wool","unlocalizedName":"block.minecraft.green_wool","localizedName":"Green Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:grindstone","unlocalizedName":"block.minecraft.grindstone","localizedName":"Grindstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:guardian_spawn_egg","unlocalizedName":"item.minecraft.guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gunpowder","unlocalizedName":"item.minecraft.gunpowder","localizedName":"Gunpowder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:hay_block","unlocalizedName":"block.minecraft.hay_block","localizedName":"Hay Bale","maxDamage":0,"maxStackSize":64},{"id":"minecraft:heart_of_the_sea","unlocalizedName":"item.minecraft.heart_of_the_sea","localizedName":"Heart of the Sea","maxDamage":0,"maxStackSize":64},{"id":"minecraft:heavy_weighted_pressure_plate","unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:honey_block","unlocalizedName":"block.minecraft.honey_block","localizedName":"Honey Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:honey_bottle","unlocalizedName":"item.minecraft.honey_bottle","localizedName":"Honey Bottle","maxDamage":0,"maxStackSize":16},{"id":"minecraft:honeycomb","unlocalizedName":"item.minecraft.honeycomb","localizedName":"Honeycomb","maxDamage":0,"maxStackSize":64},{"id":"minecraft:honeycomb_block","unlocalizedName":"block.minecraft.honeycomb_block","localizedName":"Honeycomb Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:hopper","unlocalizedName":"block.minecraft.hopper","localizedName":"Hopper","maxDamage":0,"maxStackSize":64},{"id":"minecraft:hopper_minecart","unlocalizedName":"item.minecraft.hopper_minecart","localizedName":"Minecart with Hopper","maxDamage":0,"maxStackSize":1},{"id":"minecraft:horn_coral","unlocalizedName":"block.minecraft.horn_coral","localizedName":"Horn Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:horn_coral_block","unlocalizedName":"block.minecraft.horn_coral_block","localizedName":"Horn Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:horn_coral_fan","unlocalizedName":"block.minecraft.horn_coral_fan","localizedName":"Horn Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:horse_spawn_egg","unlocalizedName":"item.minecraft.horse_spawn_egg","localizedName":"Horse Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:husk_spawn_egg","unlocalizedName":"item.minecraft.husk_spawn_egg","localizedName":"Husk Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ice","unlocalizedName":"block.minecraft.ice","localizedName":"Ice","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_chiseled_stone_bricks","unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_cobblestone","unlocalizedName":"block.minecraft.infested_cobblestone","localizedName":"Infested Cobblestone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_cracked_stone_bricks","unlocalizedName":"block.minecraft.infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_mossy_stone_bricks","unlocalizedName":"block.minecraft.infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_stone","unlocalizedName":"block.minecraft.infested_stone","localizedName":"Infested Stone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_stone_bricks","unlocalizedName":"block.minecraft.infested_stone_bricks","localizedName":"Infested Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ink_sac","unlocalizedName":"item.minecraft.ink_sac","localizedName":"Ink Sac","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_axe","unlocalizedName":"item.minecraft.iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1},{"id":"minecraft:iron_bars","unlocalizedName":"block.minecraft.iron_bars","localizedName":"Iron Bars","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_block","unlocalizedName":"block.minecraft.iron_block","localizedName":"Block of Iron","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_boots","unlocalizedName":"item.minecraft.iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1},{"id":"minecraft:iron_chestplate","unlocalizedName":"item.minecraft.iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1},{"id":"minecraft:iron_door","unlocalizedName":"block.minecraft.iron_door","localizedName":"Iron Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_helmet","unlocalizedName":"item.minecraft.iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1},{"id":"minecraft:iron_hoe","unlocalizedName":"item.minecraft.iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1},{"id":"minecraft:iron_horse_armor","unlocalizedName":"item.minecraft.iron_horse_armor","localizedName":"Iron Horse Armor","maxDamage":0,"maxStackSize":1},{"id":"minecraft:iron_ingot","unlocalizedName":"item.minecraft.iron_ingot","localizedName":"Iron Ingot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_leggings","unlocalizedName":"item.minecraft.iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1},{"id":"minecraft:iron_nugget","unlocalizedName":"item.minecraft.iron_nugget","localizedName":"Iron Nugget","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_ore","unlocalizedName":"block.minecraft.iron_ore","localizedName":"Iron Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_pickaxe","unlocalizedName":"item.minecraft.iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1},{"id":"minecraft:iron_shovel","unlocalizedName":"item.minecraft.iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1},{"id":"minecraft:iron_sword","unlocalizedName":"item.minecraft.iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1},{"id":"minecraft:iron_trapdoor","unlocalizedName":"block.minecraft.iron_trapdoor","localizedName":"Iron Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:item_frame","unlocalizedName":"item.minecraft.item_frame","localizedName":"Item Frame","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jack_o_lantern","unlocalizedName":"block.minecraft.jack_o_lantern","localizedName":"Jack o'Lantern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jigsaw","unlocalizedName":"block.minecraft.jigsaw","localizedName":"Jigsaw Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jukebox","unlocalizedName":"block.minecraft.jukebox","localizedName":"Jukebox","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_boat","unlocalizedName":"item.minecraft.jungle_boat","localizedName":"Jungle Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:jungle_button","unlocalizedName":"block.minecraft.jungle_button","localizedName":"Jungle Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_door","unlocalizedName":"block.minecraft.jungle_door","localizedName":"Jungle Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_fence","unlocalizedName":"block.minecraft.jungle_fence","localizedName":"Jungle Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_fence_gate","unlocalizedName":"block.minecraft.jungle_fence_gate","localizedName":"Jungle Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_leaves","unlocalizedName":"block.minecraft.jungle_leaves","localizedName":"Jungle Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_log","unlocalizedName":"block.minecraft.jungle_log","localizedName":"Jungle Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_planks","unlocalizedName":"block.minecraft.jungle_planks","localizedName":"Jungle Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_pressure_plate","unlocalizedName":"block.minecraft.jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_sapling","unlocalizedName":"block.minecraft.jungle_sapling","localizedName":"Jungle Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_sign","unlocalizedName":"block.minecraft.jungle_sign","localizedName":"Jungle Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:jungle_slab","unlocalizedName":"block.minecraft.jungle_slab","localizedName":"Jungle Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_stairs","unlocalizedName":"block.minecraft.jungle_stairs","localizedName":"Jungle Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_trapdoor","unlocalizedName":"block.minecraft.jungle_trapdoor","localizedName":"Jungle Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_wood","unlocalizedName":"block.minecraft.jungle_wood","localizedName":"Jungle Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:kelp","unlocalizedName":"block.minecraft.kelp","localizedName":"Kelp","maxDamage":0,"maxStackSize":64},{"id":"minecraft:knowledge_book","unlocalizedName":"item.minecraft.knowledge_book","localizedName":"Knowledge Book","maxDamage":0,"maxStackSize":1},{"id":"minecraft:ladder","unlocalizedName":"block.minecraft.ladder","localizedName":"Ladder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lantern","unlocalizedName":"block.minecraft.lantern","localizedName":"Lantern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lapis_block","unlocalizedName":"block.minecraft.lapis_block","localizedName":"Lapis Lazuli Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lapis_lazuli","unlocalizedName":"item.minecraft.lapis_lazuli","localizedName":"Lapis Lazuli","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lapis_ore","unlocalizedName":"block.minecraft.lapis_ore","localizedName":"Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:large_fern","unlocalizedName":"block.minecraft.large_fern","localizedName":"Large Fern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lava_bucket","unlocalizedName":"item.minecraft.lava_bucket","localizedName":"Lava Bucket","maxDamage":0,"maxStackSize":1},{"id":"minecraft:lead","unlocalizedName":"item.minecraft.lead","localizedName":"Lead","maxDamage":0,"maxStackSize":64},{"id":"minecraft:leather","unlocalizedName":"item.minecraft.leather","localizedName":"Leather","maxDamage":0,"maxStackSize":64},{"id":"minecraft:leather_boots","unlocalizedName":"item.minecraft.leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1},{"id":"minecraft:leather_chestplate","unlocalizedName":"item.minecraft.leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1},{"id":"minecraft:leather_helmet","unlocalizedName":"item.minecraft.leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1},{"id":"minecraft:leather_horse_armor","unlocalizedName":"item.minecraft.leather_horse_armor","localizedName":"Leather Horse Armor","maxDamage":0,"maxStackSize":1},{"id":"minecraft:leather_leggings","unlocalizedName":"item.minecraft.leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1},{"id":"minecraft:lectern","unlocalizedName":"block.minecraft.lectern","localizedName":"Lectern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lever","unlocalizedName":"block.minecraft.lever","localizedName":"Lever","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_banner","unlocalizedName":"block.minecraft.light_blue_banner","localizedName":"Light Blue Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:light_blue_bed","unlocalizedName":"block.minecraft.light_blue_bed","localizedName":"Light Blue Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:light_blue_carpet","unlocalizedName":"block.minecraft.light_blue_carpet","localizedName":"Light Blue Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_concrete","unlocalizedName":"block.minecraft.light_blue_concrete","localizedName":"Light Blue Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_concrete_powder","unlocalizedName":"block.minecraft.light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_dye","unlocalizedName":"item.minecraft.light_blue_dye","localizedName":"Light Blue Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_glazed_terracotta","unlocalizedName":"block.minecraft.light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_shulker_box","unlocalizedName":"block.minecraft.light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:light_blue_stained_glass","unlocalizedName":"block.minecraft.light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_stained_glass_pane","unlocalizedName":"block.minecraft.light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_terracotta","unlocalizedName":"block.minecraft.light_blue_terracotta","localizedName":"Light Blue Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_wool","unlocalizedName":"block.minecraft.light_blue_wool","localizedName":"Light Blue Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_banner","unlocalizedName":"block.minecraft.light_gray_banner","localizedName":"Light Gray Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:light_gray_bed","unlocalizedName":"block.minecraft.light_gray_bed","localizedName":"Light Gray Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:light_gray_carpet","unlocalizedName":"block.minecraft.light_gray_carpet","localizedName":"Light Gray Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_concrete","unlocalizedName":"block.minecraft.light_gray_concrete","localizedName":"Light Gray Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_concrete_powder","unlocalizedName":"block.minecraft.light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_dye","unlocalizedName":"item.minecraft.light_gray_dye","localizedName":"Light Gray Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_glazed_terracotta","unlocalizedName":"block.minecraft.light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_shulker_box","unlocalizedName":"block.minecraft.light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:light_gray_stained_glass","unlocalizedName":"block.minecraft.light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_stained_glass_pane","unlocalizedName":"block.minecraft.light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_terracotta","unlocalizedName":"block.minecraft.light_gray_terracotta","localizedName":"Light Gray Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_wool","unlocalizedName":"block.minecraft.light_gray_wool","localizedName":"Light Gray Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_weighted_pressure_plate","unlocalizedName":"block.minecraft.light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lilac","unlocalizedName":"block.minecraft.lilac","localizedName":"Lilac","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lily_of_the_valley","unlocalizedName":"block.minecraft.lily_of_the_valley","localizedName":"Lily of the Valley","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lily_pad","unlocalizedName":"block.minecraft.lily_pad","localizedName":"Lily Pad","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_banner","unlocalizedName":"block.minecraft.lime_banner","localizedName":"Lime Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:lime_bed","unlocalizedName":"block.minecraft.lime_bed","localizedName":"Lime Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:lime_carpet","unlocalizedName":"block.minecraft.lime_carpet","localizedName":"Lime Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_concrete","unlocalizedName":"block.minecraft.lime_concrete","localizedName":"Lime Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_concrete_powder","unlocalizedName":"block.minecraft.lime_concrete_powder","localizedName":"Lime Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_dye","unlocalizedName":"item.minecraft.lime_dye","localizedName":"Lime Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_glazed_terracotta","unlocalizedName":"block.minecraft.lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_shulker_box","unlocalizedName":"block.minecraft.lime_shulker_box","localizedName":"Lime Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:lime_stained_glass","unlocalizedName":"block.minecraft.lime_stained_glass","localizedName":"Lime Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_stained_glass_pane","unlocalizedName":"block.minecraft.lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_terracotta","unlocalizedName":"block.minecraft.lime_terracotta","localizedName":"Lime Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_wool","unlocalizedName":"block.minecraft.lime_wool","localizedName":"Lime Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lingering_potion","unlocalizedName":"item.minecraft.lingering_potion.effect.water","localizedName":"Lingering Water Bottle","maxDamage":0,"maxStackSize":1},{"id":"minecraft:llama_spawn_egg","unlocalizedName":"item.minecraft.llama_spawn_egg","localizedName":"Llama Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:loom","unlocalizedName":"block.minecraft.loom","localizedName":"Loom","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_banner","unlocalizedName":"block.minecraft.magenta_banner","localizedName":"Magenta Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:magenta_bed","unlocalizedName":"block.minecraft.magenta_bed","localizedName":"Magenta Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:magenta_carpet","unlocalizedName":"block.minecraft.magenta_carpet","localizedName":"Magenta Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_concrete","unlocalizedName":"block.minecraft.magenta_concrete","localizedName":"Magenta Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_concrete_powder","unlocalizedName":"block.minecraft.magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_dye","unlocalizedName":"item.minecraft.magenta_dye","localizedName":"Magenta Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_glazed_terracotta","unlocalizedName":"block.minecraft.magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_shulker_box","unlocalizedName":"block.minecraft.magenta_shulker_box","localizedName":"Magenta Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:magenta_stained_glass","unlocalizedName":"block.minecraft.magenta_stained_glass","localizedName":"Magenta Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_stained_glass_pane","unlocalizedName":"block.minecraft.magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_terracotta","unlocalizedName":"block.minecraft.magenta_terracotta","localizedName":"Magenta Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_wool","unlocalizedName":"block.minecraft.magenta_wool","localizedName":"Magenta Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magma_block","unlocalizedName":"block.minecraft.magma_block","localizedName":"Magma Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magma_cream","unlocalizedName":"item.minecraft.magma_cream","localizedName":"Magma Cream","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magma_cube_spawn_egg","unlocalizedName":"item.minecraft.magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:map","unlocalizedName":"item.minecraft.map","localizedName":"Empty Map","maxDamage":0,"maxStackSize":64},{"id":"minecraft:melon","unlocalizedName":"block.minecraft.melon","localizedName":"Melon","maxDamage":0,"maxStackSize":64},{"id":"minecraft:melon_seeds","unlocalizedName":"item.minecraft.melon_seeds","localizedName":"Melon Seeds","maxDamage":0,"maxStackSize":64},{"id":"minecraft:melon_slice","unlocalizedName":"item.minecraft.melon_slice","localizedName":"Melon Slice","maxDamage":0,"maxStackSize":64},{"id":"minecraft:milk_bucket","unlocalizedName":"item.minecraft.milk_bucket","localizedName":"Milk Bucket","maxDamage":0,"maxStackSize":1},{"id":"minecraft:minecart","unlocalizedName":"item.minecraft.minecart","localizedName":"Minecart","maxDamage":0,"maxStackSize":1},{"id":"minecraft:mojang_banner_pattern","unlocalizedName":"item.minecraft.mojang_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1},{"id":"minecraft:mooshroom_spawn_egg","unlocalizedName":"item.minecraft.mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_cobblestone","unlocalizedName":"block.minecraft.mossy_cobblestone","localizedName":"Mossy Cobblestone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_cobblestone_slab","unlocalizedName":"block.minecraft.mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_cobblestone_stairs","unlocalizedName":"block.minecraft.mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_cobblestone_wall","unlocalizedName":"block.minecraft.mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_stone_brick_slab","unlocalizedName":"block.minecraft.mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_stone_brick_stairs","unlocalizedName":"block.minecraft.mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_stone_brick_wall","unlocalizedName":"block.minecraft.mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_stone_bricks","unlocalizedName":"block.minecraft.mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mule_spawn_egg","unlocalizedName":"item.minecraft.mule_spawn_egg","localizedName":"Mule Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mushroom_stem","unlocalizedName":"block.minecraft.mushroom_stem","localizedName":"Mushroom Stem","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mushroom_stew","unlocalizedName":"item.minecraft.mushroom_stew","localizedName":"Mushroom Stew","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_11","unlocalizedName":"item.minecraft.music_disc_11","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_13","unlocalizedName":"item.minecraft.music_disc_13","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_blocks","unlocalizedName":"item.minecraft.music_disc_blocks","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_cat","unlocalizedName":"item.minecraft.music_disc_cat","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_chirp","unlocalizedName":"item.minecraft.music_disc_chirp","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_far","unlocalizedName":"item.minecraft.music_disc_far","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_mall","unlocalizedName":"item.minecraft.music_disc_mall","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_mellohi","unlocalizedName":"item.minecraft.music_disc_mellohi","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_stal","unlocalizedName":"item.minecraft.music_disc_stal","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_strad","unlocalizedName":"item.minecraft.music_disc_strad","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_wait","unlocalizedName":"item.minecraft.music_disc_wait","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_ward","unlocalizedName":"item.minecraft.music_disc_ward","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:mutton","unlocalizedName":"item.minecraft.mutton","localizedName":"Raw Mutton","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mycelium","unlocalizedName":"block.minecraft.mycelium","localizedName":"Mycelium","maxDamage":0,"maxStackSize":64},{"id":"minecraft:name_tag","unlocalizedName":"item.minecraft.name_tag","localizedName":"Name Tag","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nautilus_shell","unlocalizedName":"item.minecraft.nautilus_shell","localizedName":"Nautilus Shell","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_brick","unlocalizedName":"item.minecraft.nether_brick","localizedName":"Nether Brick","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_brick_fence","unlocalizedName":"block.minecraft.nether_brick_fence","localizedName":"Nether Brick Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_brick_slab","unlocalizedName":"block.minecraft.nether_brick_slab","localizedName":"Nether Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_brick_stairs","unlocalizedName":"block.minecraft.nether_brick_stairs","localizedName":"Nether Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_brick_wall","unlocalizedName":"block.minecraft.nether_brick_wall","localizedName":"Nether Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_bricks","unlocalizedName":"block.minecraft.nether_bricks","localizedName":"Nether Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_quartz_ore","unlocalizedName":"block.minecraft.nether_quartz_ore","localizedName":"Nether Quartz Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_star","unlocalizedName":"item.minecraft.nether_star","localizedName":"Nether Star","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_wart","unlocalizedName":"item.minecraft.nether_wart","localizedName":"Nether Wart","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_wart_block","unlocalizedName":"block.minecraft.nether_wart_block","localizedName":"Nether Wart Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:netherrack","unlocalizedName":"block.minecraft.netherrack","localizedName":"Netherrack","maxDamage":0,"maxStackSize":64},{"id":"minecraft:note_block","unlocalizedName":"block.minecraft.note_block","localizedName":"Note Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_boat","unlocalizedName":"item.minecraft.oak_boat","localizedName":"Oak Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:oak_button","unlocalizedName":"block.minecraft.oak_button","localizedName":"Oak Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_door","unlocalizedName":"block.minecraft.oak_door","localizedName":"Oak Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_fence","unlocalizedName":"block.minecraft.oak_fence","localizedName":"Oak Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_fence_gate","unlocalizedName":"block.minecraft.oak_fence_gate","localizedName":"Oak Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_leaves","unlocalizedName":"block.minecraft.oak_leaves","localizedName":"Oak Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_log","unlocalizedName":"block.minecraft.oak_log","localizedName":"Oak Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_planks","unlocalizedName":"block.minecraft.oak_planks","localizedName":"Oak Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_pressure_plate","unlocalizedName":"block.minecraft.oak_pressure_plate","localizedName":"Oak Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_sapling","unlocalizedName":"block.minecraft.oak_sapling","localizedName":"Oak Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_sign","unlocalizedName":"block.minecraft.oak_sign","localizedName":"Oak Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:oak_slab","unlocalizedName":"block.minecraft.oak_slab","localizedName":"Oak Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_stairs","unlocalizedName":"block.minecraft.oak_stairs","localizedName":"Oak Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_trapdoor","unlocalizedName":"block.minecraft.oak_trapdoor","localizedName":"Oak Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_wood","unlocalizedName":"block.minecraft.oak_wood","localizedName":"Oak Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:observer","unlocalizedName":"block.minecraft.observer","localizedName":"Observer","maxDamage":0,"maxStackSize":64},{"id":"minecraft:obsidian","unlocalizedName":"block.minecraft.obsidian","localizedName":"Obsidian","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ocelot_spawn_egg","unlocalizedName":"item.minecraft.ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_banner","unlocalizedName":"block.minecraft.orange_banner","localizedName":"Orange Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:orange_bed","unlocalizedName":"block.minecraft.orange_bed","localizedName":"Orange Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:orange_carpet","unlocalizedName":"block.minecraft.orange_carpet","localizedName":"Orange Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_concrete","unlocalizedName":"block.minecraft.orange_concrete","localizedName":"Orange Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_concrete_powder","unlocalizedName":"block.minecraft.orange_concrete_powder","localizedName":"Orange Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_dye","unlocalizedName":"item.minecraft.orange_dye","localizedName":"Orange Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_glazed_terracotta","unlocalizedName":"block.minecraft.orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_shulker_box","unlocalizedName":"block.minecraft.orange_shulker_box","localizedName":"Orange Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:orange_stained_glass","unlocalizedName":"block.minecraft.orange_stained_glass","localizedName":"Orange Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_stained_glass_pane","unlocalizedName":"block.minecraft.orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_terracotta","unlocalizedName":"block.minecraft.orange_terracotta","localizedName":"Orange Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_tulip","unlocalizedName":"block.minecraft.orange_tulip","localizedName":"Orange Tulip","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_wool","unlocalizedName":"block.minecraft.orange_wool","localizedName":"Orange Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oxeye_daisy","unlocalizedName":"block.minecraft.oxeye_daisy","localizedName":"Oxeye Daisy","maxDamage":0,"maxStackSize":64},{"id":"minecraft:packed_ice","unlocalizedName":"block.minecraft.packed_ice","localizedName":"Packed Ice","maxDamage":0,"maxStackSize":64},{"id":"minecraft:painting","unlocalizedName":"item.minecraft.painting","localizedName":"Painting","maxDamage":0,"maxStackSize":64},{"id":"minecraft:panda_spawn_egg","unlocalizedName":"item.minecraft.panda_spawn_egg","localizedName":"Panda Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:paper","unlocalizedName":"item.minecraft.paper","localizedName":"Paper","maxDamage":0,"maxStackSize":64},{"id":"minecraft:parrot_spawn_egg","unlocalizedName":"item.minecraft.parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:peony","unlocalizedName":"block.minecraft.peony","localizedName":"Peony","maxDamage":0,"maxStackSize":64},{"id":"minecraft:petrified_oak_slab","unlocalizedName":"block.minecraft.petrified_oak_slab","localizedName":"Petrified Oak Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:phantom_membrane","unlocalizedName":"item.minecraft.phantom_membrane","localizedName":"Phantom Membrane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:phantom_spawn_egg","unlocalizedName":"item.minecraft.phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pig_spawn_egg","unlocalizedName":"item.minecraft.pig_spawn_egg","localizedName":"Pig Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pillager_spawn_egg","unlocalizedName":"item.minecraft.pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_banner","unlocalizedName":"block.minecraft.pink_banner","localizedName":"Pink Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:pink_bed","unlocalizedName":"block.minecraft.pink_bed","localizedName":"Pink Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:pink_carpet","unlocalizedName":"block.minecraft.pink_carpet","localizedName":"Pink Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_concrete","unlocalizedName":"block.minecraft.pink_concrete","localizedName":"Pink Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_concrete_powder","unlocalizedName":"block.minecraft.pink_concrete_powder","localizedName":"Pink Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_dye","unlocalizedName":"item.minecraft.pink_dye","localizedName":"Pink Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_glazed_terracotta","unlocalizedName":"block.minecraft.pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_shulker_box","unlocalizedName":"block.minecraft.pink_shulker_box","localizedName":"Pink Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:pink_stained_glass","unlocalizedName":"block.minecraft.pink_stained_glass","localizedName":"Pink Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_stained_glass_pane","unlocalizedName":"block.minecraft.pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_terracotta","unlocalizedName":"block.minecraft.pink_terracotta","localizedName":"Pink Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_tulip","unlocalizedName":"block.minecraft.pink_tulip","localizedName":"Pink Tulip","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_wool","unlocalizedName":"block.minecraft.pink_wool","localizedName":"Pink Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:piston","unlocalizedName":"block.minecraft.piston","localizedName":"Piston","maxDamage":0,"maxStackSize":64},{"id":"minecraft:player_head","unlocalizedName":"block.minecraft.player_head","localizedName":"Player Head","maxDamage":0,"maxStackSize":64},{"id":"minecraft:podzol","unlocalizedName":"block.minecraft.podzol","localizedName":"Podzol","maxDamage":0,"maxStackSize":64},{"id":"minecraft:poisonous_potato","unlocalizedName":"item.minecraft.poisonous_potato","localizedName":"Poisonous Potato","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polar_bear_spawn_egg","unlocalizedName":"item.minecraft.polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_andesite","unlocalizedName":"block.minecraft.polished_andesite","localizedName":"Polished Andesite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_andesite_slab","unlocalizedName":"block.minecraft.polished_andesite_slab","localizedName":"Polished Andesite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_andesite_stairs","unlocalizedName":"block.minecraft.polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_diorite","unlocalizedName":"block.minecraft.polished_diorite","localizedName":"Polished Diorite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_diorite_slab","unlocalizedName":"block.minecraft.polished_diorite_slab","localizedName":"Polished Diorite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_diorite_stairs","unlocalizedName":"block.minecraft.polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_granite","unlocalizedName":"block.minecraft.polished_granite","localizedName":"Polished Granite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_granite_slab","unlocalizedName":"block.minecraft.polished_granite_slab","localizedName":"Polished Granite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_granite_stairs","unlocalizedName":"block.minecraft.polished_granite_stairs","localizedName":"Polished Granite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:popped_chorus_fruit","unlocalizedName":"item.minecraft.popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxDamage":0,"maxStackSize":64},{"id":"minecraft:poppy","unlocalizedName":"block.minecraft.poppy","localizedName":"Poppy","maxDamage":0,"maxStackSize":64},{"id":"minecraft:porkchop","unlocalizedName":"item.minecraft.porkchop","localizedName":"Raw Porkchop","maxDamage":0,"maxStackSize":64},{"id":"minecraft:potato","unlocalizedName":"item.minecraft.potato","localizedName":"Potato","maxDamage":0,"maxStackSize":64},{"id":"minecraft:potion","unlocalizedName":"item.minecraft.potion.effect.water","localizedName":"Water Bottle","maxDamage":0,"maxStackSize":1},{"id":"minecraft:powered_rail","unlocalizedName":"block.minecraft.powered_rail","localizedName":"Powered Rail","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine","unlocalizedName":"block.minecraft.prismarine","localizedName":"Prismarine","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_brick_slab","unlocalizedName":"block.minecraft.prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_brick_stairs","unlocalizedName":"block.minecraft.prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_bricks","unlocalizedName":"block.minecraft.prismarine_bricks","localizedName":"Prismarine Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_crystals","unlocalizedName":"item.minecraft.prismarine_crystals","localizedName":"Prismarine Crystals","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_shard","unlocalizedName":"item.minecraft.prismarine_shard","localizedName":"Prismarine Shard","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_slab","unlocalizedName":"block.minecraft.prismarine_slab","localizedName":"Prismarine Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_stairs","unlocalizedName":"block.minecraft.prismarine_stairs","localizedName":"Prismarine Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_wall","unlocalizedName":"block.minecraft.prismarine_wall","localizedName":"Prismarine Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pufferfish","unlocalizedName":"item.minecraft.pufferfish","localizedName":"Pufferfish","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pufferfish_bucket","unlocalizedName":"item.minecraft.pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxDamage":0,"maxStackSize":1},{"id":"minecraft:pufferfish_spawn_egg","unlocalizedName":"item.minecraft.pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pumpkin","unlocalizedName":"block.minecraft.pumpkin","localizedName":"Pumpkin","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pumpkin_pie","unlocalizedName":"item.minecraft.pumpkin_pie","localizedName":"Pumpkin Pie","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pumpkin_seeds","unlocalizedName":"item.minecraft.pumpkin_seeds","localizedName":"Pumpkin Seeds","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_banner","unlocalizedName":"block.minecraft.purple_banner","localizedName":"Purple Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:purple_bed","unlocalizedName":"block.minecraft.purple_bed","localizedName":"Purple Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:purple_carpet","unlocalizedName":"block.minecraft.purple_carpet","localizedName":"Purple Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_concrete","unlocalizedName":"block.minecraft.purple_concrete","localizedName":"Purple Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_concrete_powder","unlocalizedName":"block.minecraft.purple_concrete_powder","localizedName":"Purple Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_dye","unlocalizedName":"item.minecraft.purple_dye","localizedName":"Purple Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_glazed_terracotta","unlocalizedName":"block.minecraft.purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_shulker_box","unlocalizedName":"block.minecraft.purple_shulker_box","localizedName":"Purple Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:purple_stained_glass","unlocalizedName":"block.minecraft.purple_stained_glass","localizedName":"Purple Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_stained_glass_pane","unlocalizedName":"block.minecraft.purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_terracotta","unlocalizedName":"block.minecraft.purple_terracotta","localizedName":"Purple Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_wool","unlocalizedName":"block.minecraft.purple_wool","localizedName":"Purple Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purpur_block","unlocalizedName":"block.minecraft.purpur_block","localizedName":"Purpur Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purpur_pillar","unlocalizedName":"block.minecraft.purpur_pillar","localizedName":"Purpur Pillar","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purpur_slab","unlocalizedName":"block.minecraft.purpur_slab","localizedName":"Purpur Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purpur_stairs","unlocalizedName":"block.minecraft.purpur_stairs","localizedName":"Purpur Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:quartz","unlocalizedName":"item.minecraft.quartz","localizedName":"Nether Quartz","maxDamage":0,"maxStackSize":64},{"id":"minecraft:quartz_block","unlocalizedName":"block.minecraft.quartz_block","localizedName":"Block of Quartz","maxDamage":0,"maxStackSize":64},{"id":"minecraft:quartz_pillar","unlocalizedName":"block.minecraft.quartz_pillar","localizedName":"Quartz Pillar","maxDamage":0,"maxStackSize":64},{"id":"minecraft:quartz_slab","unlocalizedName":"block.minecraft.quartz_slab","localizedName":"Quartz Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:quartz_stairs","unlocalizedName":"block.minecraft.quartz_stairs","localizedName":"Quartz Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rabbit","unlocalizedName":"item.minecraft.rabbit","localizedName":"Raw Rabbit","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rabbit_foot","unlocalizedName":"item.minecraft.rabbit_foot","localizedName":"Rabbit's Foot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rabbit_hide","unlocalizedName":"item.minecraft.rabbit_hide","localizedName":"Rabbit Hide","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rabbit_spawn_egg","unlocalizedName":"item.minecraft.rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rabbit_stew","unlocalizedName":"item.minecraft.rabbit_stew","localizedName":"Rabbit Stew","maxDamage":0,"maxStackSize":1},{"id":"minecraft:rail","unlocalizedName":"block.minecraft.rail","localizedName":"Rail","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ravager_spawn_egg","unlocalizedName":"item.minecraft.ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_banner","unlocalizedName":"block.minecraft.red_banner","localizedName":"Red Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:red_bed","unlocalizedName":"block.minecraft.red_bed","localizedName":"Red Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:red_carpet","unlocalizedName":"block.minecraft.red_carpet","localizedName":"Red Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_concrete","unlocalizedName":"block.minecraft.red_concrete","localizedName":"Red Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_concrete_powder","unlocalizedName":"block.minecraft.red_concrete_powder","localizedName":"Red Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_dye","unlocalizedName":"item.minecraft.red_dye","localizedName":"Red Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_glazed_terracotta","unlocalizedName":"block.minecraft.red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_mushroom","unlocalizedName":"block.minecraft.red_mushroom","localizedName":"Red Mushroom","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_mushroom_block","unlocalizedName":"block.minecraft.red_mushroom_block","localizedName":"Red Mushroom Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_nether_brick_slab","unlocalizedName":"block.minecraft.red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_nether_brick_stairs","unlocalizedName":"block.minecraft.red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_nether_brick_wall","unlocalizedName":"block.minecraft.red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_nether_bricks","unlocalizedName":"block.minecraft.red_nether_bricks","localizedName":"Red Nether Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_sand","unlocalizedName":"block.minecraft.red_sand","localizedName":"Red Sand","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_sandstone","unlocalizedName":"block.minecraft.red_sandstone","localizedName":"Red Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_sandstone_slab","unlocalizedName":"block.minecraft.red_sandstone_slab","localizedName":"Red Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_sandstone_stairs","unlocalizedName":"block.minecraft.red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_sandstone_wall","unlocalizedName":"block.minecraft.red_sandstone_wall","localizedName":"Red Sandstone Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_shulker_box","unlocalizedName":"block.minecraft.red_shulker_box","localizedName":"Red Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:red_stained_glass","unlocalizedName":"block.minecraft.red_stained_glass","localizedName":"Red Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_stained_glass_pane","unlocalizedName":"block.minecraft.red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_terracotta","unlocalizedName":"block.minecraft.red_terracotta","localizedName":"Red Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_tulip","unlocalizedName":"block.minecraft.red_tulip","localizedName":"Red Tulip","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_wool","unlocalizedName":"block.minecraft.red_wool","localizedName":"Red Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:redstone","unlocalizedName":"item.minecraft.redstone","localizedName":"Redstone Dust","maxDamage":0,"maxStackSize":64},{"id":"minecraft:redstone_block","unlocalizedName":"block.minecraft.redstone_block","localizedName":"Block of Redstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:redstone_lamp","unlocalizedName":"block.minecraft.redstone_lamp","localizedName":"Redstone Lamp","maxDamage":0,"maxStackSize":64},{"id":"minecraft:redstone_ore","unlocalizedName":"block.minecraft.redstone_ore","localizedName":"Redstone Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:redstone_torch","unlocalizedName":"block.minecraft.redstone_torch","localizedName":"Redstone Torch","maxDamage":0,"maxStackSize":64},{"id":"minecraft:repeater","unlocalizedName":"block.minecraft.repeater","localizedName":"Redstone Repeater","maxDamage":0,"maxStackSize":64},{"id":"minecraft:repeating_command_block","unlocalizedName":"block.minecraft.repeating_command_block","localizedName":"Repeating Command Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rose_bush","unlocalizedName":"block.minecraft.rose_bush","localizedName":"Rose Bush","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rotten_flesh","unlocalizedName":"item.minecraft.rotten_flesh","localizedName":"Rotten Flesh","maxDamage":0,"maxStackSize":64},{"id":"minecraft:saddle","unlocalizedName":"item.minecraft.saddle","localizedName":"Saddle","maxDamage":0,"maxStackSize":1},{"id":"minecraft:salmon","unlocalizedName":"item.minecraft.salmon","localizedName":"Raw Salmon","maxDamage":0,"maxStackSize":64},{"id":"minecraft:salmon_bucket","unlocalizedName":"item.minecraft.salmon_bucket","localizedName":"Bucket of Salmon","maxDamage":0,"maxStackSize":1},{"id":"minecraft:salmon_spawn_egg","unlocalizedName":"item.minecraft.salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sand","unlocalizedName":"block.minecraft.sand","localizedName":"Sand","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sandstone","unlocalizedName":"block.minecraft.sandstone","localizedName":"Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sandstone_slab","unlocalizedName":"block.minecraft.sandstone_slab","localizedName":"Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sandstone_stairs","unlocalizedName":"block.minecraft.sandstone_stairs","localizedName":"Sandstone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sandstone_wall","unlocalizedName":"block.minecraft.sandstone_wall","localizedName":"Sandstone Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:scaffolding","unlocalizedName":"block.minecraft.scaffolding","localizedName":"Scaffolding","maxDamage":0,"maxStackSize":64},{"id":"minecraft:scute","unlocalizedName":"item.minecraft.scute","localizedName":"Scute","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sea_lantern","unlocalizedName":"block.minecraft.sea_lantern","localizedName":"Sea Lantern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sea_pickle","unlocalizedName":"block.minecraft.sea_pickle","localizedName":"Sea Pickle","maxDamage":0,"maxStackSize":64},{"id":"minecraft:seagrass","unlocalizedName":"block.minecraft.seagrass","localizedName":"Seagrass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:shears","unlocalizedName":"item.minecraft.shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1},{"id":"minecraft:sheep_spawn_egg","unlocalizedName":"item.minecraft.sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:shield","unlocalizedName":"item.minecraft.shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1},{"id":"minecraft:shulker_box","unlocalizedName":"block.minecraft.shulker_box","localizedName":"Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:shulker_shell","unlocalizedName":"item.minecraft.shulker_shell","localizedName":"Shulker Shell","maxDamage":0,"maxStackSize":64},{"id":"minecraft:shulker_spawn_egg","unlocalizedName":"item.minecraft.shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:silverfish_spawn_egg","unlocalizedName":"item.minecraft.silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:skeleton_horse_spawn_egg","unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:skeleton_skull","unlocalizedName":"block.minecraft.skeleton_skull","localizedName":"Skeleton Skull","maxDamage":0,"maxStackSize":64},{"id":"minecraft:skeleton_spawn_egg","unlocalizedName":"item.minecraft.skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:skull_banner_pattern","unlocalizedName":"item.minecraft.skull_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1},{"id":"minecraft:slime_ball","unlocalizedName":"item.minecraft.slime_ball","localizedName":"Slimeball","maxDamage":0,"maxStackSize":64},{"id":"minecraft:slime_block","unlocalizedName":"block.minecraft.slime_block","localizedName":"Slime Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:slime_spawn_egg","unlocalizedName":"item.minecraft.slime_spawn_egg","localizedName":"Slime Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smithing_table","unlocalizedName":"block.minecraft.smithing_table","localizedName":"Smithing Table","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smoker","unlocalizedName":"block.minecraft.smoker","localizedName":"Smoker","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_quartz","unlocalizedName":"block.minecraft.smooth_quartz","localizedName":"Smooth Quartz","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_quartz_slab","unlocalizedName":"block.minecraft.smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_quartz_stairs","unlocalizedName":"block.minecraft.smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_red_sandstone","unlocalizedName":"block.minecraft.smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_red_sandstone_slab","unlocalizedName":"block.minecraft.smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_red_sandstone_stairs","unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_sandstone","unlocalizedName":"block.minecraft.smooth_sandstone","localizedName":"Smooth Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_sandstone_slab","unlocalizedName":"block.minecraft.smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_sandstone_stairs","unlocalizedName":"block.minecraft.smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_stone","unlocalizedName":"block.minecraft.smooth_stone","localizedName":"Smooth Stone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_stone_slab","unlocalizedName":"block.minecraft.smooth_stone_slab","localizedName":"Smooth Stone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:snow","unlocalizedName":"block.minecraft.snow","localizedName":"Snow","maxDamage":0,"maxStackSize":64},{"id":"minecraft:snow_block","unlocalizedName":"block.minecraft.snow_block","localizedName":"Snow Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:snowball","unlocalizedName":"item.minecraft.snowball","localizedName":"Snowball","maxDamage":0,"maxStackSize":16},{"id":"minecraft:soul_sand","unlocalizedName":"block.minecraft.soul_sand","localizedName":"Soul Sand","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spawner","unlocalizedName":"block.minecraft.spawner","localizedName":"Spawner","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spectral_arrow","unlocalizedName":"item.minecraft.spectral_arrow","localizedName":"Spectral Arrow","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spider_eye","unlocalizedName":"item.minecraft.spider_eye","localizedName":"Spider Eye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spider_spawn_egg","unlocalizedName":"item.minecraft.spider_spawn_egg","localizedName":"Spider Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:splash_potion","unlocalizedName":"item.minecraft.splash_potion.effect.water","localizedName":"Splash Water Bottle","maxDamage":0,"maxStackSize":1},{"id":"minecraft:sponge","unlocalizedName":"block.minecraft.sponge","localizedName":"Sponge","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_boat","unlocalizedName":"item.minecraft.spruce_boat","localizedName":"Spruce Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:spruce_button","unlocalizedName":"block.minecraft.spruce_button","localizedName":"Spruce Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_door","unlocalizedName":"block.minecraft.spruce_door","localizedName":"Spruce Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_fence","unlocalizedName":"block.minecraft.spruce_fence","localizedName":"Spruce Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_fence_gate","unlocalizedName":"block.minecraft.spruce_fence_gate","localizedName":"Spruce Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_leaves","unlocalizedName":"block.minecraft.spruce_leaves","localizedName":"Spruce Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_log","unlocalizedName":"block.minecraft.spruce_log","localizedName":"Spruce Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_planks","unlocalizedName":"block.minecraft.spruce_planks","localizedName":"Spruce Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_pressure_plate","unlocalizedName":"block.minecraft.spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_sapling","unlocalizedName":"block.minecraft.spruce_sapling","localizedName":"Spruce Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_sign","unlocalizedName":"block.minecraft.spruce_sign","localizedName":"Spruce Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:spruce_slab","unlocalizedName":"block.minecraft.spruce_slab","localizedName":"Spruce Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_stairs","unlocalizedName":"block.minecraft.spruce_stairs","localizedName":"Spruce Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_trapdoor","unlocalizedName":"block.minecraft.spruce_trapdoor","localizedName":"Spruce Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_wood","unlocalizedName":"block.minecraft.spruce_wood","localizedName":"Spruce Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:squid_spawn_egg","unlocalizedName":"item.minecraft.squid_spawn_egg","localizedName":"Squid Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stick","unlocalizedName":"item.minecraft.stick","localizedName":"Stick","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sticky_piston","unlocalizedName":"block.minecraft.sticky_piston","localizedName":"Sticky Piston","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone","unlocalizedName":"block.minecraft.stone","localizedName":"Stone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_axe","unlocalizedName":"item.minecraft.stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1},{"id":"minecraft:stone_brick_slab","unlocalizedName":"block.minecraft.stone_brick_slab","localizedName":"Stone Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_brick_stairs","unlocalizedName":"block.minecraft.stone_brick_stairs","localizedName":"Stone Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_brick_wall","unlocalizedName":"block.minecraft.stone_brick_wall","localizedName":"Stone Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_bricks","unlocalizedName":"block.minecraft.stone_bricks","localizedName":"Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_button","unlocalizedName":"block.minecraft.stone_button","localizedName":"Stone Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_hoe","unlocalizedName":"item.minecraft.stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1},{"id":"minecraft:stone_pickaxe","unlocalizedName":"item.minecraft.stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1},{"id":"minecraft:stone_pressure_plate","unlocalizedName":"block.minecraft.stone_pressure_plate","localizedName":"Stone Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_shovel","unlocalizedName":"item.minecraft.stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1},{"id":"minecraft:stone_slab","unlocalizedName":"block.minecraft.stone_slab","localizedName":"Stone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_stairs","unlocalizedName":"block.minecraft.stone_stairs","localizedName":"Stone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_sword","unlocalizedName":"item.minecraft.stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1},{"id":"minecraft:stonecutter","unlocalizedName":"block.minecraft.stonecutter","localizedName":"Stonecutter","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stray_spawn_egg","unlocalizedName":"item.minecraft.stray_spawn_egg","localizedName":"Stray Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:string","unlocalizedName":"item.minecraft.string","localizedName":"String","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_acacia_log","unlocalizedName":"block.minecraft.stripped_acacia_log","localizedName":"Stripped Acacia Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_acacia_wood","unlocalizedName":"block.minecraft.stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_birch_log","unlocalizedName":"block.minecraft.stripped_birch_log","localizedName":"Stripped Birch Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_birch_wood","unlocalizedName":"block.minecraft.stripped_birch_wood","localizedName":"Stripped Birch Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_dark_oak_log","unlocalizedName":"block.minecraft.stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_dark_oak_wood","unlocalizedName":"block.minecraft.stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_jungle_log","unlocalizedName":"block.minecraft.stripped_jungle_log","localizedName":"Stripped Jungle Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_jungle_wood","unlocalizedName":"block.minecraft.stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_oak_log","unlocalizedName":"block.minecraft.stripped_oak_log","localizedName":"Stripped Oak Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_oak_wood","unlocalizedName":"block.minecraft.stripped_oak_wood","localizedName":"Stripped Oak Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_spruce_log","unlocalizedName":"block.minecraft.stripped_spruce_log","localizedName":"Stripped Spruce Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_spruce_wood","unlocalizedName":"block.minecraft.stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:structure_block","unlocalizedName":"block.minecraft.structure_block","localizedName":"Structure Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:structure_void","unlocalizedName":"block.minecraft.structure_void","localizedName":"Structure Void","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sugar","unlocalizedName":"item.minecraft.sugar","localizedName":"Sugar","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sugar_cane","unlocalizedName":"block.minecraft.sugar_cane","localizedName":"Sugar Cane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sunflower","unlocalizedName":"block.minecraft.sunflower","localizedName":"Sunflower","maxDamage":0,"maxStackSize":64},{"id":"minecraft:suspicious_stew","unlocalizedName":"item.minecraft.suspicious_stew","localizedName":"Suspicious Stew","maxDamage":0,"maxStackSize":1},{"id":"minecraft:sweet_berries","unlocalizedName":"item.minecraft.sweet_berries","localizedName":"Sweet Berries","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tall_grass","unlocalizedName":"block.minecraft.tall_grass","localizedName":"Tall Grass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:terracotta","unlocalizedName":"block.minecraft.terracotta","localizedName":"Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tipped_arrow","unlocalizedName":"item.minecraft.tipped_arrow.effect.poison","localizedName":"Arrow of Poison","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tnt","unlocalizedName":"block.minecraft.tnt","localizedName":"TNT","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tnt_minecart","unlocalizedName":"item.minecraft.tnt_minecart","localizedName":"Minecart with TNT","maxDamage":0,"maxStackSize":1},{"id":"minecraft:torch","unlocalizedName":"block.minecraft.torch","localizedName":"Torch","maxDamage":0,"maxStackSize":64},{"id":"minecraft:totem_of_undying","unlocalizedName":"item.minecraft.totem_of_undying","localizedName":"Totem of Undying","maxDamage":0,"maxStackSize":1},{"id":"minecraft:trader_llama_spawn_egg","unlocalizedName":"item.minecraft.trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:trapped_chest","unlocalizedName":"block.minecraft.trapped_chest","localizedName":"Trapped Chest","maxDamage":0,"maxStackSize":64},{"id":"minecraft:trident","unlocalizedName":"item.minecraft.trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1},{"id":"minecraft:tripwire_hook","unlocalizedName":"block.minecraft.tripwire_hook","localizedName":"Tripwire Hook","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tropical_fish","unlocalizedName":"item.minecraft.tropical_fish","localizedName":"Tropical Fish","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tropical_fish_bucket","unlocalizedName":"item.minecraft.tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxDamage":0,"maxStackSize":1},{"id":"minecraft:tropical_fish_spawn_egg","unlocalizedName":"item.minecraft.tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tube_coral","unlocalizedName":"block.minecraft.tube_coral","localizedName":"Tube Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tube_coral_block","unlocalizedName":"block.minecraft.tube_coral_block","localizedName":"Tube Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tube_coral_fan","unlocalizedName":"block.minecraft.tube_coral_fan","localizedName":"Tube Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:turtle_egg","unlocalizedName":"block.minecraft.turtle_egg","localizedName":"Turtle Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:turtle_helmet","unlocalizedName":"item.minecraft.turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1},{"id":"minecraft:turtle_spawn_egg","unlocalizedName":"item.minecraft.turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:vex_spawn_egg","unlocalizedName":"item.minecraft.vex_spawn_egg","localizedName":"Vex Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:villager_spawn_egg","unlocalizedName":"item.minecraft.villager_spawn_egg","localizedName":"Villager Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:vindicator_spawn_egg","unlocalizedName":"item.minecraft.vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:vine","unlocalizedName":"block.minecraft.vine","localizedName":"Vines","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wandering_trader_spawn_egg","unlocalizedName":"item.minecraft.wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:water_bucket","unlocalizedName":"item.minecraft.water_bucket","localizedName":"Water Bucket","maxDamage":0,"maxStackSize":1},{"id":"minecraft:wet_sponge","unlocalizedName":"block.minecraft.wet_sponge","localizedName":"Wet Sponge","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wheat","unlocalizedName":"item.minecraft.wheat","localizedName":"Wheat","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wheat_seeds","unlocalizedName":"item.minecraft.wheat_seeds","localizedName":"Wheat Seeds","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_banner","unlocalizedName":"block.minecraft.white_banner","localizedName":"White Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:white_bed","unlocalizedName":"block.minecraft.white_bed","localizedName":"White Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:white_carpet","unlocalizedName":"block.minecraft.white_carpet","localizedName":"White Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_concrete","unlocalizedName":"block.minecraft.white_concrete","localizedName":"White Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_concrete_powder","unlocalizedName":"block.minecraft.white_concrete_powder","localizedName":"White Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_dye","unlocalizedName":"item.minecraft.white_dye","localizedName":"White Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_glazed_terracotta","unlocalizedName":"block.minecraft.white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_shulker_box","unlocalizedName":"block.minecraft.white_shulker_box","localizedName":"White Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:white_stained_glass","unlocalizedName":"block.minecraft.white_stained_glass","localizedName":"White Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_stained_glass_pane","unlocalizedName":"block.minecraft.white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_terracotta","unlocalizedName":"block.minecraft.white_terracotta","localizedName":"White Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_tulip","unlocalizedName":"block.minecraft.white_tulip","localizedName":"White Tulip","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_wool","unlocalizedName":"block.minecraft.white_wool","localizedName":"White Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:witch_spawn_egg","unlocalizedName":"item.minecraft.witch_spawn_egg","localizedName":"Witch Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wither_rose","unlocalizedName":"block.minecraft.wither_rose","localizedName":"Wither Rose","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wither_skeleton_skull","unlocalizedName":"block.minecraft.wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wither_skeleton_spawn_egg","unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wolf_spawn_egg","unlocalizedName":"item.minecraft.wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wooden_axe","unlocalizedName":"item.minecraft.wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1},{"id":"minecraft:wooden_hoe","unlocalizedName":"item.minecraft.wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1},{"id":"minecraft:wooden_pickaxe","unlocalizedName":"item.minecraft.wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1},{"id":"minecraft:wooden_shovel","unlocalizedName":"item.minecraft.wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1},{"id":"minecraft:wooden_sword","unlocalizedName":"item.minecraft.wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1},{"id":"minecraft:writable_book","unlocalizedName":"item.minecraft.writable_book","localizedName":"Book and Quill","maxDamage":0,"maxStackSize":1},{"id":"minecraft:written_book","unlocalizedName":"item.minecraft.written_book","localizedName":"Written Book","maxDamage":0,"maxStackSize":16},{"id":"minecraft:yellow_banner","unlocalizedName":"block.minecraft.yellow_banner","localizedName":"Yellow Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:yellow_bed","unlocalizedName":"block.minecraft.yellow_bed","localizedName":"Yellow Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:yellow_carpet","unlocalizedName":"block.minecraft.yellow_carpet","localizedName":"Yellow Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_concrete","unlocalizedName":"block.minecraft.yellow_concrete","localizedName":"Yellow Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_concrete_powder","unlocalizedName":"block.minecraft.yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_dye","unlocalizedName":"item.minecraft.yellow_dye","localizedName":"Yellow Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_glazed_terracotta","unlocalizedName":"block.minecraft.yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_shulker_box","unlocalizedName":"block.minecraft.yellow_shulker_box","localizedName":"Yellow Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:yellow_stained_glass","unlocalizedName":"block.minecraft.yellow_stained_glass","localizedName":"Yellow Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_stained_glass_pane","unlocalizedName":"block.minecraft.yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_terracotta","unlocalizedName":"block.minecraft.yellow_terracotta","localizedName":"Yellow Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_wool","unlocalizedName":"block.minecraft.yellow_wool","localizedName":"Yellow Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:zombie_head","unlocalizedName":"block.minecraft.zombie_head","localizedName":"Zombie Head","maxDamage":0,"maxStackSize":64},{"id":"minecraft:zombie_horse_spawn_egg","unlocalizedName":"item.minecraft.zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:zombie_pigman_spawn_egg","unlocalizedName":"item.minecraft.zombie_pigman_spawn_egg","localizedName":"Zombie Pigman Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:zombie_spawn_egg","unlocalizedName":"item.minecraft.zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:zombie_villager_spawn_egg","unlocalizedName":"item.minecraft.zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxDamage":0,"maxStackSize":64}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/items.116.json b/src/main/resources/com/sk89q/worldedit/world/registry/items.116.json new file mode 100644 index 0000000..5430596 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/items.116.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_boat","localizedName":"Acacia Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_boat"},{"id":"minecraft:acacia_button","localizedName":"Acacia Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_button"},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_door"},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence"},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence_gate"},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_leaves"},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_log"},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_planks"},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_pressure_plate"},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_sapling"},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_sign"},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_slab"},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_stairs"},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_trapdoor"},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_wood"},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.activator_rail"},{"id":"minecraft:air","localizedName":"Air","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.air"},{"id":"minecraft:allium","localizedName":"Allium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.allium"},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ancient_debris"},{"id":"minecraft:andesite","localizedName":"Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite"},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_slab"},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_stairs"},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_wall"},{"id":"minecraft:anvil","localizedName":"Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.anvil"},{"id":"minecraft:apple","localizedName":"Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.apple"},{"id":"minecraft:armor_stand","localizedName":"Armor Stand","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.armor_stand"},{"id":"minecraft:arrow","localizedName":"Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.arrow"},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azure_bluet"},{"id":"minecraft:baked_potato","localizedName":"Baked Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.baked_potato"},{"id":"minecraft:bamboo","localizedName":"Bamboo","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo"},{"id":"minecraft:barrel","localizedName":"Barrel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrel"},{"id":"minecraft:barrier","localizedName":"Barrier","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrier"},{"id":"minecraft:basalt","localizedName":"Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.basalt"},{"id":"minecraft:bat_spawn_egg","localizedName":"Bat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bat_spawn_egg"},{"id":"minecraft:beacon","localizedName":"Beacon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beacon"},{"id":"minecraft:bedrock","localizedName":"Bedrock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bedrock"},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bee_nest"},{"id":"minecraft:bee_spawn_egg","localizedName":"Bee Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bee_spawn_egg"},{"id":"minecraft:beef","localizedName":"Raw Beef","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beef"},{"id":"minecraft:beehive","localizedName":"Beehive","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beehive"},{"id":"minecraft:beetroot","localizedName":"Beetroot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot"},{"id":"minecraft:beetroot_seeds","localizedName":"Beetroot Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot_seeds"},{"id":"minecraft:beetroot_soup","localizedName":"Beetroot Soup","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.beetroot_soup"},{"id":"minecraft:bell","localizedName":"Bell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bell"},{"id":"minecraft:birch_boat","localizedName":"Birch Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.birch_boat"},{"id":"minecraft:birch_button","localizedName":"Birch Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_button"},{"id":"minecraft:birch_door","localizedName":"Birch Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_door"},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence"},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence_gate"},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_leaves"},{"id":"minecraft:birch_log","localizedName":"Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_log"},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_planks"},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_pressure_plate"},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_sapling"},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.birch_sign"},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_slab"},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_stairs"},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_trapdoor"},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_wood"},{"id":"minecraft:black_banner","localizedName":"Black Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.black_banner"},{"id":"minecraft:black_bed","localizedName":"Black Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_bed"},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_carpet"},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete"},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete_powder"},{"id":"minecraft:black_dye","localizedName":"Black Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.black_dye"},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_glazed_terracotta"},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_shulker_box"},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass"},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass_pane"},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_terracotta"},{"id":"minecraft:black_wool","localizedName":"Black Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_wool"},{"id":"minecraft:blackstone","localizedName":"Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone"},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_slab"},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_stairs"},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_wall"},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blast_furnace"},{"id":"minecraft:blaze_powder","localizedName":"Blaze Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_powder"},{"id":"minecraft:blaze_rod","localizedName":"Blaze Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_rod"},{"id":"minecraft:blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_spawn_egg"},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.blue_banner"},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_bed"},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_carpet"},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete"},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete_powder"},{"id":"minecraft:blue_dye","localizedName":"Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blue_dye"},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_glazed_terracotta"},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_ice"},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_orchid"},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_shulker_box"},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass"},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass_pane"},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_terracotta"},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_wool"},{"id":"minecraft:bone","localizedName":"Bone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone"},{"id":"minecraft:bone_block","localizedName":"Bone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bone_block"},{"id":"minecraft:bone_meal","localizedName":"Bone Meal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone_meal"},{"id":"minecraft:book","localizedName":"Book","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.book"},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bookshelf"},{"id":"minecraft:bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1,"unlocalizedName":"item.minecraft.bow"},{"id":"minecraft:bowl","localizedName":"Bowl","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bowl"},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral"},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_block"},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_fan"},{"id":"minecraft:bread","localizedName":"Bread","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bread"},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brewing_stand"},{"id":"minecraft:brick","localizedName":"Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brick"},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_slab"},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_stairs"},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_wall"},{"id":"minecraft:bricks","localizedName":"Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bricks"},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.brown_banner"},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_bed"},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_carpet"},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete"},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete_powder"},{"id":"minecraft:brown_dye","localizedName":"Brown Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brown_dye"},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_glazed_terracotta"},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom"},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom_block"},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_shulker_box"},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass"},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass_pane"},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_terracotta"},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_wool"},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral"},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_block"},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_fan"},{"id":"minecraft:bucket","localizedName":"Bucket","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.bucket"},{"id":"minecraft:cactus","localizedName":"Cactus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cactus"},{"id":"minecraft:cake","localizedName":"Cake","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cake"},{"id":"minecraft:campfire","localizedName":"Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.campfire"},{"id":"minecraft:carrot","localizedName":"Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.carrot"},{"id":"minecraft:carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1,"unlocalizedName":"item.minecraft.carrot_on_a_stick"},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cartography_table"},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.carved_pumpkin"},{"id":"minecraft:cat_spawn_egg","localizedName":"Cat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cat_spawn_egg"},{"id":"minecraft:cauldron","localizedName":"Cauldron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cauldron"},{"id":"minecraft:cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cave_spider_spawn_egg"},{"id":"minecraft:chain","localizedName":"Chain","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain"},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain_command_block"},{"id":"minecraft:chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_boots"},{"id":"minecraft:chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_chestplate"},{"id":"minecraft:chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_helmet"},{"id":"minecraft:chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_leggings"},{"id":"minecraft:charcoal","localizedName":"Charcoal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.charcoal"},{"id":"minecraft:chest","localizedName":"Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chest"},{"id":"minecraft:chest_minecart","localizedName":"Minecart with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.chest_minecart"},{"id":"minecraft:chicken","localizedName":"Raw Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken"},{"id":"minecraft:chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken_spawn_egg"},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chipped_anvil"},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_nether_bricks"},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_polished_blackstone"},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_quartz_block"},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_red_sandstone"},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_sandstone"},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_stone_bricks"},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_flower"},{"id":"minecraft:chorus_fruit","localizedName":"Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chorus_fruit"},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_plant"},{"id":"minecraft:clay","localizedName":"Clay","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.clay"},{"id":"minecraft:clay_ball","localizedName":"Clay Ball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clay_ball"},{"id":"minecraft:clock","localizedName":"Clock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clock"},{"id":"minecraft:coal","localizedName":"Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.coal"},{"id":"minecraft:coal_block","localizedName":"Block of Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_block"},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_ore"},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coarse_dirt"},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone"},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_slab"},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_stairs"},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_wall"},{"id":"minecraft:cobweb","localizedName":"Cobweb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobweb"},{"id":"minecraft:cocoa_beans","localizedName":"Cocoa Beans","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cocoa_beans"},{"id":"minecraft:cod","localizedName":"Raw Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod"},{"id":"minecraft:cod_bucket","localizedName":"Bucket of Cod","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.cod_bucket"},{"id":"minecraft:cod_spawn_egg","localizedName":"Cod Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod_spawn_egg"},{"id":"minecraft:command_block","localizedName":"Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.command_block"},{"id":"minecraft:command_block_minecart","localizedName":"Minecart with Command Block","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.command_block_minecart"},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.comparator"},{"id":"minecraft:compass","localizedName":"Compass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.compass"},{"id":"minecraft:composter","localizedName":"Composter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.composter"},{"id":"minecraft:conduit","localizedName":"Conduit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.conduit"},{"id":"minecraft:cooked_beef","localizedName":"Steak","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_beef"},{"id":"minecraft:cooked_chicken","localizedName":"Cooked Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_chicken"},{"id":"minecraft:cooked_cod","localizedName":"Cooked Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_cod"},{"id":"minecraft:cooked_mutton","localizedName":"Cooked Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_mutton"},{"id":"minecraft:cooked_porkchop","localizedName":"Cooked Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_porkchop"},{"id":"minecraft:cooked_rabbit","localizedName":"Cooked Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_rabbit"},{"id":"minecraft:cooked_salmon","localizedName":"Cooked Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_salmon"},{"id":"minecraft:cookie","localizedName":"Cookie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cookie"},{"id":"minecraft:cornflower","localizedName":"Cornflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cornflower"},{"id":"minecraft:cow_spawn_egg","localizedName":"Cow Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cow_spawn_egg"},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_nether_bricks"},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_polished_blackstone_bricks"},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_stone_bricks"},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crafting_table"},{"id":"minecraft:creeper_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.creeper_banner_pattern"},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.creeper_head"},{"id":"minecraft:creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.creeper_spawn_egg"},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_button"},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_door"},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence"},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence_gate"},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fungus"},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_hyphae"},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_nylium"},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_planks"},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_pressure_plate"},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_roots"},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_sign"},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_slab"},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stairs"},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stem"},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_trapdoor"},{"id":"minecraft:crossbow","localizedName":"Crossbow","maxDamage":326,"maxStackSize":1,"unlocalizedName":"item.minecraft.crossbow"},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crying_obsidian"},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone"},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone_slab"},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone"},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone_slab"},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.cyan_banner"},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_bed"},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_carpet"},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete"},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete_powder"},{"id":"minecraft:cyan_dye","localizedName":"Cyan Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cyan_dye"},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_glazed_terracotta"},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_shulker_box"},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass"},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass_pane"},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_terracotta"},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_wool"},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.damaged_anvil"},{"id":"minecraft:dandelion","localizedName":"Dandelion","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dandelion"},{"id":"minecraft:dark_oak_boat","localizedName":"Dark Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_boat"},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_button"},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_door"},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence"},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence_gate"},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_leaves"},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_log"},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_planks"},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_pressure_plate"},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_sapling"},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_sign"},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_slab"},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_stairs"},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_trapdoor"},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_wood"},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine"},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_slab"},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_stairs"},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.daylight_detector"},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral"},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_block"},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_fan"},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral"},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_block"},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_fan"},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bush"},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral"},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_block"},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_fan"},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral"},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_block"},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_fan"},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral"},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_block"},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_fan"},{"id":"minecraft:debug_stick","localizedName":"Debug Stick","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.debug_stick"},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.detector_rail"},{"id":"minecraft:diamond","localizedName":"Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.diamond"},{"id":"minecraft:diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_axe"},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_block"},{"id":"minecraft:diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_boots"},{"id":"minecraft:diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_chestplate"},{"id":"minecraft:diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_helmet"},{"id":"minecraft:diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_hoe"},{"id":"minecraft:diamond_horse_armor","localizedName":"Diamond Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_horse_armor"},{"id":"minecraft:diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_leggings"},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_ore"},{"id":"minecraft:diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_pickaxe"},{"id":"minecraft:diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_shovel"},{"id":"minecraft:diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_sword"},{"id":"minecraft:diorite","localizedName":"Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite"},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_slab"},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_stairs"},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_wall"},{"id":"minecraft:dirt","localizedName":"Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt"},{"id":"minecraft:dispenser","localizedName":"Dispenser","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dispenser"},{"id":"minecraft:dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dolphin_spawn_egg"},{"id":"minecraft:donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.donkey_spawn_egg"},{"id":"minecraft:dragon_breath","localizedName":"Dragon's Breath","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dragon_breath"},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_egg"},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_head"},{"id":"minecraft:dried_kelp","localizedName":"Dried Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dried_kelp"},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dried_kelp_block"},{"id":"minecraft:dropper","localizedName":"Dropper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dropper"},{"id":"minecraft:drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.drowned_spawn_egg"},{"id":"minecraft:egg","localizedName":"Egg","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.egg"},{"id":"minecraft:elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.elder_guardian_spawn_egg"},{"id":"minecraft:elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1,"unlocalizedName":"item.minecraft.elytra"},{"id":"minecraft:emerald","localizedName":"Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.emerald"},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_block"},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_ore"},{"id":"minecraft:enchanted_book","localizedName":"Enchanted Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.enchanted_book"},{"id":"minecraft:enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enchanted_golden_apple"},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.enchanting_table"},{"id":"minecraft:end_crystal","localizedName":"End Crystal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.end_crystal"},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_portal_frame"},{"id":"minecraft:end_rod","localizedName":"End Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_rod"},{"id":"minecraft:end_stone","localizedName":"End Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone"},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_slab"},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_stairs"},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_wall"},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_bricks"},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ender_chest"},{"id":"minecraft:ender_eye","localizedName":"Eye of Ender","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ender_eye"},{"id":"minecraft:ender_pearl","localizedName":"Ender Pearl","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.ender_pearl"},{"id":"minecraft:enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enderman_spawn_egg"},{"id":"minecraft:endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.endermite_spawn_egg"},{"id":"minecraft:evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.evoker_spawn_egg"},{"id":"minecraft:experience_bottle","localizedName":"Bottle o' Enchanting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.experience_bottle"},{"id":"minecraft:farmland","localizedName":"Farmland","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.farmland"},{"id":"minecraft:feather","localizedName":"Feather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.feather"},{"id":"minecraft:fermented_spider_eye","localizedName":"Fermented Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fermented_spider_eye"},{"id":"minecraft:fern","localizedName":"Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fern"},{"id":"minecraft:filled_map","localizedName":"Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.filled_map"},{"id":"minecraft:fire_charge","localizedName":"Fire Charge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fire_charge"},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral"},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_block"},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_fan"},{"id":"minecraft:firework_rocket","localizedName":"Firework Rocket","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_rocket"},{"id":"minecraft:firework_star","localizedName":"Firework Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_star"},{"id":"minecraft:fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.fishing_rod"},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fletching_table"},{"id":"minecraft:flint","localizedName":"Flint","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.flint"},{"id":"minecraft:flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.flint_and_steel"},{"id":"minecraft:flower_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.flower_banner_pattern"},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flower_pot"},{"id":"minecraft:fox_spawn_egg","localizedName":"Fox Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fox_spawn_egg"},{"id":"minecraft:furnace","localizedName":"Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.furnace"},{"id":"minecraft:furnace_minecart","localizedName":"Minecart with Furnace","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.furnace_minecart"},{"id":"minecraft:ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_spawn_egg"},{"id":"minecraft:ghast_tear","localizedName":"Ghast Tear","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_tear"},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gilded_blackstone"},{"id":"minecraft:glass","localizedName":"Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass"},{"id":"minecraft:glass_bottle","localizedName":"Glass Bottle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glass_bottle"},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass_pane"},{"id":"minecraft:glistering_melon_slice","localizedName":"Glistering Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glistering_melon_slice"},{"id":"minecraft:globe_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.globe_banner_pattern"},{"id":"minecraft:glowstone","localizedName":"Glowstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glowstone"},{"id":"minecraft:glowstone_dust","localizedName":"Glowstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glowstone_dust"},{"id":"minecraft:gold_block","localizedName":"Block of Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_block"},{"id":"minecraft:gold_ingot","localizedName":"Gold Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_ingot"},{"id":"minecraft:gold_nugget","localizedName":"Gold Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_nugget"},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_ore"},{"id":"minecraft:golden_apple","localizedName":"Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_apple"},{"id":"minecraft:golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_axe"},{"id":"minecraft:golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_boots"},{"id":"minecraft:golden_carrot","localizedName":"Golden Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_carrot"},{"id":"minecraft:golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_chestplate"},{"id":"minecraft:golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_helmet"},{"id":"minecraft:golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_hoe"},{"id":"minecraft:golden_horse_armor","localizedName":"Golden Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_horse_armor"},{"id":"minecraft:golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_leggings"},{"id":"minecraft:golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_pickaxe"},{"id":"minecraft:golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_shovel"},{"id":"minecraft:golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_sword"},{"id":"minecraft:granite","localizedName":"Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite"},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_slab"},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_stairs"},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_wall"},{"id":"minecraft:grass","localizedName":"Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass"},{"id":"minecraft:grass_block","localizedName":"Grass Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass_block"},{"id":"minecraft:grass_path","localizedName":"Grass Path","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass_path"},{"id":"minecraft:gravel","localizedName":"Gravel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gravel"},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.gray_banner"},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_bed"},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_carpet"},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete"},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete_powder"},{"id":"minecraft:gray_dye","localizedName":"Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gray_dye"},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_glazed_terracotta"},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_shulker_box"},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass"},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass_pane"},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_terracotta"},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_wool"},{"id":"minecraft:green_banner","localizedName":"Green Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.green_banner"},{"id":"minecraft:green_bed","localizedName":"Green Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_bed"},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_carpet"},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete"},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete_powder"},{"id":"minecraft:green_dye","localizedName":"Green Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.green_dye"},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_glazed_terracotta"},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_shulker_box"},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass"},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass_pane"},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_terracotta"},{"id":"minecraft:green_wool","localizedName":"Green Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_wool"},{"id":"minecraft:grindstone","localizedName":"Grindstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grindstone"},{"id":"minecraft:guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.guardian_spawn_egg"},{"id":"minecraft:gunpowder","localizedName":"Gunpowder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gunpowder"},{"id":"minecraft:hay_block","localizedName":"Hay Bale","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hay_block"},{"id":"minecraft:heart_of_the_sea","localizedName":"Heart of the Sea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.heart_of_the_sea"},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate"},{"id":"minecraft:hoglin_spawn_egg","localizedName":"Hoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.hoglin_spawn_egg"},{"id":"minecraft:honey_block","localizedName":"Honey Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honey_block"},{"id":"minecraft:honey_bottle","localizedName":"Honey Bottle","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.honey_bottle"},{"id":"minecraft:honeycomb","localizedName":"Honeycomb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.honeycomb"},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honeycomb_block"},{"id":"minecraft:hopper","localizedName":"Hopper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hopper"},{"id":"minecraft:hopper_minecart","localizedName":"Minecart with Hopper","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.hopper_minecart"},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral"},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_block"},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_fan"},{"id":"minecraft:horse_spawn_egg","localizedName":"Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.horse_spawn_egg"},{"id":"minecraft:husk_spawn_egg","localizedName":"Husk Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.husk_spawn_egg"},{"id":"minecraft:ice","localizedName":"Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ice"},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks"},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cobblestone"},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cracked_stone_bricks"},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_mossy_stone_bricks"},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone"},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone_bricks"},{"id":"minecraft:ink_sac","localizedName":"Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ink_sac"},{"id":"minecraft:iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_axe"},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_bars"},{"id":"minecraft:iron_block","localizedName":"Block of Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_block"},{"id":"minecraft:iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_boots"},{"id":"minecraft:iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_chestplate"},{"id":"minecraft:iron_door","localizedName":"Iron Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_door"},{"id":"minecraft:iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_helmet"},{"id":"minecraft:iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_hoe"},{"id":"minecraft:iron_horse_armor","localizedName":"Iron Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_horse_armor"},{"id":"minecraft:iron_ingot","localizedName":"Iron Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_ingot"},{"id":"minecraft:iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_leggings"},{"id":"minecraft:iron_nugget","localizedName":"Iron Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_nugget"},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_ore"},{"id":"minecraft:iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_pickaxe"},{"id":"minecraft:iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_shovel"},{"id":"minecraft:iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_sword"},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_trapdoor"},{"id":"minecraft:item_frame","localizedName":"Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.item_frame"},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o'Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jack_o_lantern"},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jigsaw"},{"id":"minecraft:jukebox","localizedName":"Jukebox","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jukebox"},{"id":"minecraft:jungle_boat","localizedName":"Jungle Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_boat"},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_button"},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_door"},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence"},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence_gate"},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_leaves"},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_log"},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_planks"},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_pressure_plate"},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_sapling"},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_sign"},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_slab"},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_stairs"},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_trapdoor"},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_wood"},{"id":"minecraft:kelp","localizedName":"Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.kelp"},{"id":"minecraft:knowledge_book","localizedName":"Knowledge Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.knowledge_book"},{"id":"minecraft:ladder","localizedName":"Ladder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ladder"},{"id":"minecraft:lantern","localizedName":"Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lantern"},{"id":"minecraft:lapis_block","localizedName":"Lapis Lazuli Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_block"},{"id":"minecraft:lapis_lazuli","localizedName":"Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lapis_lazuli"},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_ore"},{"id":"minecraft:large_fern","localizedName":"Large Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_fern"},{"id":"minecraft:lava_bucket","localizedName":"Lava Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lava_bucket"},{"id":"minecraft:lead","localizedName":"Lead","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lead"},{"id":"minecraft:leather","localizedName":"Leather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.leather"},{"id":"minecraft:leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_boots"},{"id":"minecraft:leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_chestplate"},{"id":"minecraft:leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_helmet"},{"id":"minecraft:leather_horse_armor","localizedName":"Leather Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_horse_armor"},{"id":"minecraft:leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_leggings"},{"id":"minecraft:lectern","localizedName":"Lectern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lectern"},{"id":"minecraft:lever","localizedName":"Lever","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lever"},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_blue_banner"},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_bed"},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_carpet"},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete"},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete_powder"},{"id":"minecraft:light_blue_dye","localizedName":"Light Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_blue_dye"},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_glazed_terracotta"},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_shulker_box"},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass"},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass_pane"},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_terracotta"},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_wool"},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_gray_banner"},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_bed"},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_carpet"},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete"},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete_powder"},{"id":"minecraft:light_gray_dye","localizedName":"Light Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_gray_dye"},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_glazed_terracotta"},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_shulker_box"},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass"},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass_pane"},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_terracotta"},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_wool"},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_weighted_pressure_plate"},{"id":"minecraft:lilac","localizedName":"Lilac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lilac"},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_of_the_valley"},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_pad"},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.lime_banner"},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_bed"},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_carpet"},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete"},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete_powder"},{"id":"minecraft:lime_dye","localizedName":"Lime Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lime_dye"},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_glazed_terracotta"},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_shulker_box"},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass"},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass_pane"},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_terracotta"},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_wool"},{"id":"minecraft:lingering_potion","localizedName":"Lingering Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lingering_potion.effect.water"},{"id":"minecraft:llama_spawn_egg","localizedName":"Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.llama_spawn_egg"},{"id":"minecraft:lodestone","localizedName":"Lodestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lodestone"},{"id":"minecraft:loom","localizedName":"Loom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.loom"},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.magenta_banner"},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_bed"},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_carpet"},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete"},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete_powder"},{"id":"minecraft:magenta_dye","localizedName":"Magenta Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magenta_dye"},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_glazed_terracotta"},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_shulker_box"},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass"},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass_pane"},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_terracotta"},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_wool"},{"id":"minecraft:magma_block","localizedName":"Magma Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magma_block"},{"id":"minecraft:magma_cream","localizedName":"Magma Cream","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cream"},{"id":"minecraft:magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cube_spawn_egg"},{"id":"minecraft:map","localizedName":"Empty Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.map"},{"id":"minecraft:melon","localizedName":"Melon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.melon"},{"id":"minecraft:melon_seeds","localizedName":"Melon Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_seeds"},{"id":"minecraft:melon_slice","localizedName":"Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_slice"},{"id":"minecraft:milk_bucket","localizedName":"Milk Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.milk_bucket"},{"id":"minecraft:minecart","localizedName":"Minecart","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.minecart"},{"id":"minecraft:mojang_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mojang_banner_pattern"},{"id":"minecraft:mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mooshroom_spawn_egg"},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone"},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_slab"},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_stairs"},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_wall"},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_slab"},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_stairs"},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_wall"},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_bricks"},{"id":"minecraft:mule_spawn_egg","localizedName":"Mule Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mule_spawn_egg"},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mushroom_stem"},{"id":"minecraft:mushroom_stew","localizedName":"Mushroom Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mushroom_stew"},{"id":"minecraft:music_disc_11","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_11"},{"id":"minecraft:music_disc_13","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_13"},{"id":"minecraft:music_disc_blocks","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_blocks"},{"id":"minecraft:music_disc_cat","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_cat"},{"id":"minecraft:music_disc_chirp","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_chirp"},{"id":"minecraft:music_disc_far","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_far"},{"id":"minecraft:music_disc_mall","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mall"},{"id":"minecraft:music_disc_mellohi","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mellohi"},{"id":"minecraft:music_disc_pigstep","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_pigstep"},{"id":"minecraft:music_disc_stal","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_stal"},{"id":"minecraft:music_disc_strad","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_strad"},{"id":"minecraft:music_disc_wait","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_wait"},{"id":"minecraft:music_disc_ward","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_ward"},{"id":"minecraft:mutton","localizedName":"Raw Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mutton"},{"id":"minecraft:mycelium","localizedName":"Mycelium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mycelium"},{"id":"minecraft:name_tag","localizedName":"Name Tag","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.name_tag"},{"id":"minecraft:nautilus_shell","localizedName":"Nautilus Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nautilus_shell"},{"id":"minecraft:nether_brick","localizedName":"Nether Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_brick"},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_fence"},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_slab"},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_stairs"},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_wall"},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_bricks"},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_gold_ore"},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_quartz_ore"},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_sprouts"},{"id":"minecraft:nether_star","localizedName":"Nether Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_star"},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_wart"},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_wart_block"},{"id":"minecraft:netherite_axe","localizedName":"Netherite Axe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_axe"},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherite_block"},{"id":"minecraft:netherite_boots","localizedName":"Netherite Boots","maxDamage":481,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_boots"},{"id":"minecraft:netherite_chestplate","localizedName":"Netherite Chestplate","maxDamage":592,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_chestplate"},{"id":"minecraft:netherite_helmet","localizedName":"Netherite Helmet","maxDamage":407,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_helmet"},{"id":"minecraft:netherite_hoe","localizedName":"Netherite Hoe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_hoe"},{"id":"minecraft:netherite_ingot","localizedName":"Netherite Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_ingot"},{"id":"minecraft:netherite_leggings","localizedName":"Netherite Leggings","maxDamage":555,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_leggings"},{"id":"minecraft:netherite_pickaxe","localizedName":"Netherite Pickaxe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_pickaxe"},{"id":"minecraft:netherite_scrap","localizedName":"Netherite Scrap","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_scrap"},{"id":"minecraft:netherite_shovel","localizedName":"Netherite Shovel","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_shovel"},{"id":"minecraft:netherite_sword","localizedName":"Netherite Sword","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_sword"},{"id":"minecraft:netherrack","localizedName":"Netherrack","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherrack"},{"id":"minecraft:note_block","localizedName":"Note Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.note_block"},{"id":"minecraft:oak_boat","localizedName":"Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.oak_boat"},{"id":"minecraft:oak_button","localizedName":"Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_button"},{"id":"minecraft:oak_door","localizedName":"Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_door"},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence"},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence_gate"},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_leaves"},{"id":"minecraft:oak_log","localizedName":"Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_log"},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_planks"},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_pressure_plate"},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_sapling"},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.oak_sign"},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_slab"},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_stairs"},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_trapdoor"},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_wood"},{"id":"minecraft:observer","localizedName":"Observer","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.observer"},{"id":"minecraft:obsidian","localizedName":"Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.obsidian"},{"id":"minecraft:ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ocelot_spawn_egg"},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.orange_banner"},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_bed"},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_carpet"},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete"},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete_powder"},{"id":"minecraft:orange_dye","localizedName":"Orange Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.orange_dye"},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_glazed_terracotta"},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_shulker_box"},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass"},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass_pane"},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_terracotta"},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_tulip"},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_wool"},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxeye_daisy"},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.packed_ice"},{"id":"minecraft:painting","localizedName":"Painting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.painting"},{"id":"minecraft:panda_spawn_egg","localizedName":"Panda Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.panda_spawn_egg"},{"id":"minecraft:paper","localizedName":"Paper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.paper"},{"id":"minecraft:parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.parrot_spawn_egg"},{"id":"minecraft:peony","localizedName":"Peony","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.peony"},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.petrified_oak_slab"},{"id":"minecraft:phantom_membrane","localizedName":"Phantom Membrane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_membrane"},{"id":"minecraft:phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_spawn_egg"},{"id":"minecraft:pig_spawn_egg","localizedName":"Pig Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pig_spawn_egg"},{"id":"minecraft:piglin_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.piglin_banner_pattern"},{"id":"minecraft:piglin_brute_spawn_egg","localizedName":"Piglin Brute Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_brute_spawn_egg"},{"id":"minecraft:piglin_spawn_egg","localizedName":"Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_spawn_egg"},{"id":"minecraft:pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pillager_spawn_egg"},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.pink_banner"},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_bed"},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_carpet"},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete"},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete_powder"},{"id":"minecraft:pink_dye","localizedName":"Pink Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pink_dye"},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_glazed_terracotta"},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_shulker_box"},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass"},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass_pane"},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_terracotta"},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_tulip"},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_wool"},{"id":"minecraft:piston","localizedName":"Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.piston"},{"id":"minecraft:player_head","localizedName":"Player Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.player_head"},{"id":"minecraft:podzol","localizedName":"Podzol","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.podzol"},{"id":"minecraft:poisonous_potato","localizedName":"Poisonous Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.poisonous_potato"},{"id":"minecraft:polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.polar_bear_spawn_egg"},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite"},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_slab"},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_stairs"},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_basalt"},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone"},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_slab"},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_stairs"},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_wall"},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_bricks"},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_button"},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_pressure_plate"},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_slab"},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_stairs"},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_wall"},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite"},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_slab"},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_stairs"},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite"},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_slab"},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_stairs"},{"id":"minecraft:popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.popped_chorus_fruit"},{"id":"minecraft:poppy","localizedName":"Poppy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.poppy"},{"id":"minecraft:porkchop","localizedName":"Raw Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.porkchop"},{"id":"minecraft:potato","localizedName":"Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.potato"},{"id":"minecraft:potion","localizedName":"Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.potion.effect.water"},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.powered_rail"},{"id":"minecraft:prismarine","localizedName":"Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine"},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_slab"},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_stairs"},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_bricks"},{"id":"minecraft:prismarine_crystals","localizedName":"Prismarine Crystals","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_crystals"},{"id":"minecraft:prismarine_shard","localizedName":"Prismarine Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_shard"},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_slab"},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_stairs"},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_wall"},{"id":"minecraft:pufferfish","localizedName":"Pufferfish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish"},{"id":"minecraft:pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.pufferfish_bucket"},{"id":"minecraft:pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish_spawn_egg"},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pumpkin"},{"id":"minecraft:pumpkin_pie","localizedName":"Pumpkin Pie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_pie"},{"id":"minecraft:pumpkin_seeds","localizedName":"Pumpkin Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_seeds"},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.purple_banner"},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_bed"},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_carpet"},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete"},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete_powder"},{"id":"minecraft:purple_dye","localizedName":"Purple Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.purple_dye"},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_glazed_terracotta"},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_shulker_box"},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass"},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass_pane"},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_terracotta"},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_wool"},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_block"},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_pillar"},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_slab"},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_stairs"},{"id":"minecraft:quartz","localizedName":"Nether Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.quartz"},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_block"},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_bricks"},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_pillar"},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_slab"},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_stairs"},{"id":"minecraft:rabbit","localizedName":"Raw Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit"},{"id":"minecraft:rabbit_foot","localizedName":"Rabbit's Foot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_foot"},{"id":"minecraft:rabbit_hide","localizedName":"Rabbit Hide","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_hide"},{"id":"minecraft:rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_spawn_egg"},{"id":"minecraft:rabbit_stew","localizedName":"Rabbit Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.rabbit_stew"},{"id":"minecraft:rail","localizedName":"Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rail"},{"id":"minecraft:ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ravager_spawn_egg"},{"id":"minecraft:red_banner","localizedName":"Red Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.red_banner"},{"id":"minecraft:red_bed","localizedName":"Red Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_bed"},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_carpet"},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete"},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete_powder"},{"id":"minecraft:red_dye","localizedName":"Red Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.red_dye"},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_glazed_terracotta"},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom"},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom_block"},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_slab"},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_stairs"},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_wall"},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_bricks"},{"id":"minecraft:red_sand","localizedName":"Red Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sand"},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone"},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_slab"},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_stairs"},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_wall"},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_shulker_box"},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass"},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass_pane"},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_terracotta"},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_tulip"},{"id":"minecraft:red_wool","localizedName":"Red Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_wool"},{"id":"minecraft:redstone","localizedName":"Redstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.redstone"},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_block"},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_lamp"},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_ore"},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_torch"},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeater"},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeating_command_block"},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.respawn_anchor"},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rose_bush"},{"id":"minecraft:rotten_flesh","localizedName":"Rotten Flesh","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rotten_flesh"},{"id":"minecraft:saddle","localizedName":"Saddle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.saddle"},{"id":"minecraft:salmon","localizedName":"Raw Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon"},{"id":"minecraft:salmon_bucket","localizedName":"Bucket of Salmon","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.salmon_bucket"},{"id":"minecraft:salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon_spawn_egg"},{"id":"minecraft:sand","localizedName":"Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sand"},{"id":"minecraft:sandstone","localizedName":"Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone"},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_slab"},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_stairs"},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_wall"},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.scaffolding"},{"id":"minecraft:scute","localizedName":"Scute","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.scute"},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_lantern"},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_pickle"},{"id":"minecraft:seagrass","localizedName":"Seagrass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.seagrass"},{"id":"minecraft:shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1,"unlocalizedName":"item.minecraft.shears"},{"id":"minecraft:sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sheep_spawn_egg"},{"id":"minecraft:shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1,"unlocalizedName":"item.minecraft.shield"},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.shroomlight"},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.shulker_box"},{"id":"minecraft:shulker_shell","localizedName":"Shulker Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_shell"},{"id":"minecraft:shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_spawn_egg"},{"id":"minecraft:silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.silverfish_spawn_egg"},{"id":"minecraft:skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg"},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.skeleton_skull"},{"id":"minecraft:skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_spawn_egg"},{"id":"minecraft:skull_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.skull_banner_pattern"},{"id":"minecraft:slime_ball","localizedName":"Slimeball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_ball"},{"id":"minecraft:slime_block","localizedName":"Slime Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.slime_block"},{"id":"minecraft:slime_spawn_egg","localizedName":"Slime Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_spawn_egg"},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smithing_table"},{"id":"minecraft:smoker","localizedName":"Smoker","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smoker"},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz"},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_slab"},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_stairs"},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone"},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_slab"},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs"},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone"},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_slab"},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_stairs"},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone"},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone_slab"},{"id":"minecraft:snow","localizedName":"Snow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow"},{"id":"minecraft:snow_block","localizedName":"Snow Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow_block"},{"id":"minecraft:snowball","localizedName":"Snowball","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.snowball"},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_campfire"},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_lantern"},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_sand"},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_soil"},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_torch"},{"id":"minecraft:spawner","localizedName":"Spawner","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spawner"},{"id":"minecraft:spectral_arrow","localizedName":"Spectral Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spectral_arrow"},{"id":"minecraft:spider_eye","localizedName":"Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_eye"},{"id":"minecraft:spider_spawn_egg","localizedName":"Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_spawn_egg"},{"id":"minecraft:splash_potion","localizedName":"Splash Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.splash_potion.effect.water"},{"id":"minecraft:sponge","localizedName":"Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sponge"},{"id":"minecraft:spruce_boat","localizedName":"Spruce Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_boat"},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_button"},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_door"},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence"},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence_gate"},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_leaves"},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_log"},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_planks"},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_pressure_plate"},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_sapling"},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_sign"},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_slab"},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_stairs"},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_trapdoor"},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_wood"},{"id":"minecraft:squid_spawn_egg","localizedName":"Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.squid_spawn_egg"},{"id":"minecraft:stick","localizedName":"Stick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stick"},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sticky_piston"},{"id":"minecraft:stone","localizedName":"Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone"},{"id":"minecraft:stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_axe"},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_slab"},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_stairs"},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_wall"},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_bricks"},{"id":"minecraft:stone_button","localizedName":"Stone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_button"},{"id":"minecraft:stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_hoe"},{"id":"minecraft:stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_pickaxe"},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_pressure_plate"},{"id":"minecraft:stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_shovel"},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_slab"},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_stairs"},{"id":"minecraft:stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_sword"},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stonecutter"},{"id":"minecraft:stray_spawn_egg","localizedName":"Stray Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stray_spawn_egg"},{"id":"minecraft:strider_spawn_egg","localizedName":"Strider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.strider_spawn_egg"},{"id":"minecraft:string","localizedName":"String","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.string"},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_log"},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_wood"},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_log"},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_wood"},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_hyphae"},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_stem"},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_log"},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_wood"},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_log"},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_wood"},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_log"},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_wood"},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_log"},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_wood"},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_hyphae"},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_stem"},{"id":"minecraft:structure_block","localizedName":"Structure Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_block"},{"id":"minecraft:structure_void","localizedName":"Structure Void","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_void"},{"id":"minecraft:sugar","localizedName":"Sugar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sugar"},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sugar_cane"},{"id":"minecraft:sunflower","localizedName":"Sunflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sunflower"},{"id":"minecraft:suspicious_stew","localizedName":"Suspicious Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.suspicious_stew"},{"id":"minecraft:sweet_berries","localizedName":"Sweet Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sweet_berries"},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tall_grass"},{"id":"minecraft:target","localizedName":"Target","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.target"},{"id":"minecraft:terracotta","localizedName":"Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.terracotta"},{"id":"minecraft:tipped_arrow","localizedName":"Arrow of Poison","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tipped_arrow.effect.poison"},{"id":"minecraft:tnt","localizedName":"TNT","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tnt"},{"id":"minecraft:tnt_minecart","localizedName":"Minecart with TNT","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tnt_minecart"},{"id":"minecraft:torch","localizedName":"Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.torch"},{"id":"minecraft:totem_of_undying","localizedName":"Totem of Undying","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.totem_of_undying"},{"id":"minecraft:trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.trader_llama_spawn_egg"},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.trapped_chest"},{"id":"minecraft:trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.trident"},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tripwire_hook"},{"id":"minecraft:tropical_fish","localizedName":"Tropical Fish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish"},{"id":"minecraft:tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tropical_fish_bucket"},{"id":"minecraft:tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish_spawn_egg"},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral"},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_block"},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_fan"},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.turtle_egg"},{"id":"minecraft:turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1,"unlocalizedName":"item.minecraft.turtle_helmet"},{"id":"minecraft:turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_spawn_egg"},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.twisting_vines"},{"id":"minecraft:vex_spawn_egg","localizedName":"Vex Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vex_spawn_egg"},{"id":"minecraft:villager_spawn_egg","localizedName":"Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.villager_spawn_egg"},{"id":"minecraft:vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vindicator_spawn_egg"},{"id":"minecraft:vine","localizedName":"Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.vine"},{"id":"minecraft:wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wandering_trader_spawn_egg"},{"id":"minecraft:warped_button","localizedName":"Warped Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_button"},{"id":"minecraft:warped_door","localizedName":"Warped Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_door"},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence"},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence_gate"},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fungus"},{"id":"minecraft:warped_fungus_on_a_stick","localizedName":"Warped Fungus on a Stick","maxDamage":100,"maxStackSize":1,"unlocalizedName":"item.minecraft.warped_fungus_on_a_stick"},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_hyphae"},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_nylium"},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_planks"},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_pressure_plate"},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_roots"},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.warped_sign"},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_slab"},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stairs"},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stem"},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_trapdoor"},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_wart_block"},{"id":"minecraft:water_bucket","localizedName":"Water Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.water_bucket"},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weeping_vines"},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wet_sponge"},{"id":"minecraft:wheat","localizedName":"Wheat","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat"},{"id":"minecraft:wheat_seeds","localizedName":"Wheat Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat_seeds"},{"id":"minecraft:white_banner","localizedName":"White Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.white_banner"},{"id":"minecraft:white_bed","localizedName":"White Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_bed"},{"id":"minecraft:white_carpet","localizedName":"White Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_carpet"},{"id":"minecraft:white_concrete","localizedName":"White Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete"},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete_powder"},{"id":"minecraft:white_dye","localizedName":"White Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.white_dye"},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_glazed_terracotta"},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_shulker_box"},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass"},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass_pane"},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_terracotta"},{"id":"minecraft:white_tulip","localizedName":"White Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_tulip"},{"id":"minecraft:white_wool","localizedName":"White Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_wool"},{"id":"minecraft:witch_spawn_egg","localizedName":"Witch Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.witch_spawn_egg"},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_rose"},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_skeleton_skull"},{"id":"minecraft:wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg"},{"id":"minecraft:wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wolf_spawn_egg"},{"id":"minecraft:wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_axe"},{"id":"minecraft:wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_hoe"},{"id":"minecraft:wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_pickaxe"},{"id":"minecraft:wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_shovel"},{"id":"minecraft:wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_sword"},{"id":"minecraft:writable_book","localizedName":"Book and Quill","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.writable_book"},{"id":"minecraft:written_book","localizedName":"Written Book","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.written_book"},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.yellow_banner"},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_bed"},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_carpet"},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete"},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete_powder"},{"id":"minecraft:yellow_dye","localizedName":"Yellow Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.yellow_dye"},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_glazed_terracotta"},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_shulker_box"},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass"},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass_pane"},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_terracotta"},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_wool"},{"id":"minecraft:zoglin_spawn_egg","localizedName":"Zoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zoglin_spawn_egg"},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.zombie_head"},{"id":"minecraft:zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_horse_spawn_egg"},{"id":"minecraft:zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_spawn_egg"},{"id":"minecraft:zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_villager_spawn_egg"},{"id":"minecraft:zombified_piglin_spawn_egg","localizedName":"Zombified Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombified_piglin_spawn_egg"}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/items.117.json b/src/main/resources/com/sk89q/worldedit/world/registry/items.117.json new file mode 100644 index 0000000..d11bafa --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/items.117.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_boat","localizedName":"Acacia Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_boat"},{"id":"minecraft:acacia_button","localizedName":"Acacia Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_button"},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_door"},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence"},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence_gate"},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_leaves"},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_log"},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_planks"},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_pressure_plate"},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_sapling"},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_sign"},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_slab"},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_stairs"},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_trapdoor"},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_wood"},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.activator_rail"},{"id":"minecraft:air","localizedName":"Air","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.air"},{"id":"minecraft:allium","localizedName":"Allium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.allium"},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_block"},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_cluster"},{"id":"minecraft:amethyst_shard","localizedName":"Amethyst Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.amethyst_shard"},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ancient_debris"},{"id":"minecraft:andesite","localizedName":"Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite"},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_slab"},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_stairs"},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_wall"},{"id":"minecraft:anvil","localizedName":"Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.anvil"},{"id":"minecraft:apple","localizedName":"Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.apple"},{"id":"minecraft:armor_stand","localizedName":"Armor Stand","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.armor_stand"},{"id":"minecraft:arrow","localizedName":"Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.arrow"},{"id":"minecraft:axolotl_bucket","localizedName":"Bucket of Axolotl","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.axolotl_bucket"},{"id":"minecraft:axolotl_spawn_egg","localizedName":"Axolotl Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.axolotl_spawn_egg"},{"id":"minecraft:azalea","localizedName":"Azalea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azalea"},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azalea_leaves"},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azure_bluet"},{"id":"minecraft:baked_potato","localizedName":"Baked Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.baked_potato"},{"id":"minecraft:bamboo","localizedName":"Bamboo","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo"},{"id":"minecraft:barrel","localizedName":"Barrel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrel"},{"id":"minecraft:barrier","localizedName":"Barrier","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrier"},{"id":"minecraft:basalt","localizedName":"Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.basalt"},{"id":"minecraft:bat_spawn_egg","localizedName":"Bat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bat_spawn_egg"},{"id":"minecraft:beacon","localizedName":"Beacon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beacon"},{"id":"minecraft:bedrock","localizedName":"Bedrock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bedrock"},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bee_nest"},{"id":"minecraft:bee_spawn_egg","localizedName":"Bee Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bee_spawn_egg"},{"id":"minecraft:beef","localizedName":"Raw Beef","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beef"},{"id":"minecraft:beehive","localizedName":"Beehive","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beehive"},{"id":"minecraft:beetroot","localizedName":"Beetroot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot"},{"id":"minecraft:beetroot_seeds","localizedName":"Beetroot Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot_seeds"},{"id":"minecraft:beetroot_soup","localizedName":"Beetroot Soup","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.beetroot_soup"},{"id":"minecraft:bell","localizedName":"Bell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bell"},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.big_dripleaf"},{"id":"minecraft:birch_boat","localizedName":"Birch Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.birch_boat"},{"id":"minecraft:birch_button","localizedName":"Birch Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_button"},{"id":"minecraft:birch_door","localizedName":"Birch Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_door"},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence"},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence_gate"},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_leaves"},{"id":"minecraft:birch_log","localizedName":"Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_log"},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_planks"},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_pressure_plate"},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_sapling"},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.birch_sign"},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_slab"},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_stairs"},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_trapdoor"},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_wood"},{"id":"minecraft:black_banner","localizedName":"Black Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.black_banner"},{"id":"minecraft:black_bed","localizedName":"Black Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_bed"},{"id":"minecraft:black_candle","localizedName":"Black Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_candle"},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_carpet"},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete"},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete_powder"},{"id":"minecraft:black_dye","localizedName":"Black Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.black_dye"},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_glazed_terracotta"},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_shulker_box"},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass"},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass_pane"},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_terracotta"},{"id":"minecraft:black_wool","localizedName":"Black Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_wool"},{"id":"minecraft:blackstone","localizedName":"Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone"},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_slab"},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_stairs"},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_wall"},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blast_furnace"},{"id":"minecraft:blaze_powder","localizedName":"Blaze Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_powder"},{"id":"minecraft:blaze_rod","localizedName":"Blaze Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_rod"},{"id":"minecraft:blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_spawn_egg"},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.blue_banner"},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_bed"},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_candle"},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_carpet"},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete"},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete_powder"},{"id":"minecraft:blue_dye","localizedName":"Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blue_dye"},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_glazed_terracotta"},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_ice"},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_orchid"},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_shulker_box"},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass"},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass_pane"},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_terracotta"},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_wool"},{"id":"minecraft:bone","localizedName":"Bone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone"},{"id":"minecraft:bone_block","localizedName":"Bone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bone_block"},{"id":"minecraft:bone_meal","localizedName":"Bone Meal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone_meal"},{"id":"minecraft:book","localizedName":"Book","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.book"},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bookshelf"},{"id":"minecraft:bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1,"unlocalizedName":"item.minecraft.bow"},{"id":"minecraft:bowl","localizedName":"Bowl","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bowl"},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral"},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_block"},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_fan"},{"id":"minecraft:bread","localizedName":"Bread","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bread"},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brewing_stand"},{"id":"minecraft:brick","localizedName":"Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brick"},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_slab"},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_stairs"},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_wall"},{"id":"minecraft:bricks","localizedName":"Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bricks"},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.brown_banner"},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_bed"},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_candle"},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_carpet"},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete"},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete_powder"},{"id":"minecraft:brown_dye","localizedName":"Brown Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brown_dye"},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_glazed_terracotta"},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom"},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom_block"},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_shulker_box"},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass"},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass_pane"},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_terracotta"},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_wool"},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral"},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_block"},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_fan"},{"id":"minecraft:bucket","localizedName":"Bucket","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.bucket"},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.budding_amethyst"},{"id":"minecraft:bundle","localizedName":"Bundle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.bundle"},{"id":"minecraft:cactus","localizedName":"Cactus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cactus"},{"id":"minecraft:cake","localizedName":"Cake","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cake"},{"id":"minecraft:calcite","localizedName":"Calcite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.calcite"},{"id":"minecraft:campfire","localizedName":"Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.campfire"},{"id":"minecraft:candle","localizedName":"Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.candle"},{"id":"minecraft:carrot","localizedName":"Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.carrot"},{"id":"minecraft:carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1,"unlocalizedName":"item.minecraft.carrot_on_a_stick"},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cartography_table"},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.carved_pumpkin"},{"id":"minecraft:cat_spawn_egg","localizedName":"Cat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cat_spawn_egg"},{"id":"minecraft:cauldron","localizedName":"Cauldron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cauldron"},{"id":"minecraft:cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cave_spider_spawn_egg"},{"id":"minecraft:chain","localizedName":"Chain","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain"},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain_command_block"},{"id":"minecraft:chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_boots"},{"id":"minecraft:chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_chestplate"},{"id":"minecraft:chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_helmet"},{"id":"minecraft:chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_leggings"},{"id":"minecraft:charcoal","localizedName":"Charcoal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.charcoal"},{"id":"minecraft:chest","localizedName":"Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chest"},{"id":"minecraft:chest_minecart","localizedName":"Minecart with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.chest_minecart"},{"id":"minecraft:chicken","localizedName":"Raw Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken"},{"id":"minecraft:chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken_spawn_egg"},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chipped_anvil"},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_deepslate"},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_nether_bricks"},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_polished_blackstone"},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_quartz_block"},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_red_sandstone"},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_sandstone"},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_stone_bricks"},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_flower"},{"id":"minecraft:chorus_fruit","localizedName":"Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chorus_fruit"},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_plant"},{"id":"minecraft:clay","localizedName":"Clay","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.clay"},{"id":"minecraft:clay_ball","localizedName":"Clay Ball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clay_ball"},{"id":"minecraft:clock","localizedName":"Clock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clock"},{"id":"minecraft:coal","localizedName":"Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.coal"},{"id":"minecraft:coal_block","localizedName":"Block of Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_block"},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_ore"},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coarse_dirt"},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate"},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_slab"},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_stairs"},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_wall"},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone"},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_slab"},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_stairs"},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_wall"},{"id":"minecraft:cobweb","localizedName":"Cobweb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobweb"},{"id":"minecraft:cocoa_beans","localizedName":"Cocoa Beans","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cocoa_beans"},{"id":"minecraft:cod","localizedName":"Raw Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod"},{"id":"minecraft:cod_bucket","localizedName":"Bucket of Cod","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.cod_bucket"},{"id":"minecraft:cod_spawn_egg","localizedName":"Cod Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod_spawn_egg"},{"id":"minecraft:command_block","localizedName":"Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.command_block"},{"id":"minecraft:command_block_minecart","localizedName":"Minecart with Command Block","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.command_block_minecart"},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.comparator"},{"id":"minecraft:compass","localizedName":"Compass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.compass"},{"id":"minecraft:composter","localizedName":"Composter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.composter"},{"id":"minecraft:conduit","localizedName":"Conduit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.conduit"},{"id":"minecraft:cooked_beef","localizedName":"Steak","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_beef"},{"id":"minecraft:cooked_chicken","localizedName":"Cooked Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_chicken"},{"id":"minecraft:cooked_cod","localizedName":"Cooked Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_cod"},{"id":"minecraft:cooked_mutton","localizedName":"Cooked Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_mutton"},{"id":"minecraft:cooked_porkchop","localizedName":"Cooked Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_porkchop"},{"id":"minecraft:cooked_rabbit","localizedName":"Cooked Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_rabbit"},{"id":"minecraft:cooked_salmon","localizedName":"Cooked Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_salmon"},{"id":"minecraft:cookie","localizedName":"Cookie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cookie"},{"id":"minecraft:copper_block","localizedName":"Block of Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.copper_block"},{"id":"minecraft:copper_ingot","localizedName":"Copper Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.copper_ingot"},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.copper_ore"},{"id":"minecraft:cornflower","localizedName":"Cornflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cornflower"},{"id":"minecraft:cow_spawn_egg","localizedName":"Cow Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cow_spawn_egg"},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_bricks"},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_tiles"},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_nether_bricks"},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_polished_blackstone_bricks"},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_stone_bricks"},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crafting_table"},{"id":"minecraft:creeper_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.creeper_banner_pattern"},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.creeper_head"},{"id":"minecraft:creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.creeper_spawn_egg"},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_button"},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_door"},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence"},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence_gate"},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fungus"},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_hyphae"},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_nylium"},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_planks"},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_pressure_plate"},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_roots"},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_sign"},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_slab"},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stairs"},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stem"},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_trapdoor"},{"id":"minecraft:crossbow","localizedName":"Crossbow","maxDamage":326,"maxStackSize":1,"unlocalizedName":"item.minecraft.crossbow"},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crying_obsidian"},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper"},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_slab"},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_stairs"},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone"},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone_slab"},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone"},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone_slab"},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.cyan_banner"},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_bed"},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_candle"},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_carpet"},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete"},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete_powder"},{"id":"minecraft:cyan_dye","localizedName":"Cyan Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cyan_dye"},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_glazed_terracotta"},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_shulker_box"},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass"},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass_pane"},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_terracotta"},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_wool"},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.damaged_anvil"},{"id":"minecraft:dandelion","localizedName":"Dandelion","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dandelion"},{"id":"minecraft:dark_oak_boat","localizedName":"Dark Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_boat"},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_button"},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_door"},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence"},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence_gate"},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_leaves"},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_log"},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_planks"},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_pressure_plate"},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_sapling"},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_sign"},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_slab"},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_stairs"},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_trapdoor"},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_wood"},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine"},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_slab"},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_stairs"},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.daylight_detector"},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral"},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_block"},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_fan"},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral"},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_block"},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_fan"},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bush"},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral"},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_block"},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_fan"},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral"},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_block"},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_fan"},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral"},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_block"},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_fan"},{"id":"minecraft:debug_stick","localizedName":"Debug Stick","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.debug_stick"},{"id":"minecraft:deepslate","localizedName":"Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate"},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_slab"},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_stairs"},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_wall"},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_bricks"},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_coal_ore"},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_copper_ore"},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_diamond_ore"},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_emerald_ore"},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_gold_ore"},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_iron_ore"},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_lapis_ore"},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_redstone_ore"},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_slab"},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_stairs"},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_wall"},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tiles"},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.detector_rail"},{"id":"minecraft:diamond","localizedName":"Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.diamond"},{"id":"minecraft:diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_axe"},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_block"},{"id":"minecraft:diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_boots"},{"id":"minecraft:diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_chestplate"},{"id":"minecraft:diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_helmet"},{"id":"minecraft:diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_hoe"},{"id":"minecraft:diamond_horse_armor","localizedName":"Diamond Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_horse_armor"},{"id":"minecraft:diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_leggings"},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_ore"},{"id":"minecraft:diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_pickaxe"},{"id":"minecraft:diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_shovel"},{"id":"minecraft:diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_sword"},{"id":"minecraft:diorite","localizedName":"Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite"},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_slab"},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_stairs"},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_wall"},{"id":"minecraft:dirt","localizedName":"Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt"},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt_path"},{"id":"minecraft:dispenser","localizedName":"Dispenser","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dispenser"},{"id":"minecraft:dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dolphin_spawn_egg"},{"id":"minecraft:donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.donkey_spawn_egg"},{"id":"minecraft:dragon_breath","localizedName":"Dragon\u0027s Breath","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dragon_breath"},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_egg"},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_head"},{"id":"minecraft:dried_kelp","localizedName":"Dried Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dried_kelp"},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dried_kelp_block"},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dripstone_block"},{"id":"minecraft:dropper","localizedName":"Dropper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dropper"},{"id":"minecraft:drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.drowned_spawn_egg"},{"id":"minecraft:egg","localizedName":"Egg","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.egg"},{"id":"minecraft:elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.elder_guardian_spawn_egg"},{"id":"minecraft:elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1,"unlocalizedName":"item.minecraft.elytra"},{"id":"minecraft:emerald","localizedName":"Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.emerald"},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_block"},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_ore"},{"id":"minecraft:enchanted_book","localizedName":"Enchanted Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.enchanted_book"},{"id":"minecraft:enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enchanted_golden_apple"},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.enchanting_table"},{"id":"minecraft:end_crystal","localizedName":"End Crystal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.end_crystal"},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_portal_frame"},{"id":"minecraft:end_rod","localizedName":"End Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_rod"},{"id":"minecraft:end_stone","localizedName":"End Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone"},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_slab"},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_stairs"},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_wall"},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_bricks"},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ender_chest"},{"id":"minecraft:ender_eye","localizedName":"Eye of Ender","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ender_eye"},{"id":"minecraft:ender_pearl","localizedName":"Ender Pearl","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.ender_pearl"},{"id":"minecraft:enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enderman_spawn_egg"},{"id":"minecraft:endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.endermite_spawn_egg"},{"id":"minecraft:evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.evoker_spawn_egg"},{"id":"minecraft:experience_bottle","localizedName":"Bottle o\u0027 Enchanting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.experience_bottle"},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper"},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper"},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_slab"},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_stairs"},{"id":"minecraft:farmland","localizedName":"Farmland","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.farmland"},{"id":"minecraft:feather","localizedName":"Feather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.feather"},{"id":"minecraft:fermented_spider_eye","localizedName":"Fermented Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fermented_spider_eye"},{"id":"minecraft:fern","localizedName":"Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fern"},{"id":"minecraft:filled_map","localizedName":"Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.filled_map"},{"id":"minecraft:fire_charge","localizedName":"Fire Charge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fire_charge"},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral"},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_block"},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_fan"},{"id":"minecraft:firework_rocket","localizedName":"Firework Rocket","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_rocket"},{"id":"minecraft:firework_star","localizedName":"Firework Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_star"},{"id":"minecraft:fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.fishing_rod"},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fletching_table"},{"id":"minecraft:flint","localizedName":"Flint","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.flint"},{"id":"minecraft:flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.flint_and_steel"},{"id":"minecraft:flower_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.flower_banner_pattern"},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flower_pot"},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea"},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea_leaves"},{"id":"minecraft:fox_spawn_egg","localizedName":"Fox Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fox_spawn_egg"},{"id":"minecraft:furnace","localizedName":"Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.furnace"},{"id":"minecraft:furnace_minecart","localizedName":"Minecart with Furnace","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.furnace_minecart"},{"id":"minecraft:ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_spawn_egg"},{"id":"minecraft:ghast_tear","localizedName":"Ghast Tear","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_tear"},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gilded_blackstone"},{"id":"minecraft:glass","localizedName":"Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass"},{"id":"minecraft:glass_bottle","localizedName":"Glass Bottle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glass_bottle"},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass_pane"},{"id":"minecraft:glistering_melon_slice","localizedName":"Glistering Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glistering_melon_slice"},{"id":"minecraft:globe_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.globe_banner_pattern"},{"id":"minecraft:glow_berries","localizedName":"Glow Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_berries"},{"id":"minecraft:glow_ink_sac","localizedName":"Glow Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_ink_sac"},{"id":"minecraft:glow_item_frame","localizedName":"Glow Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_item_frame"},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glow_lichen"},{"id":"minecraft:glow_squid_spawn_egg","localizedName":"Glow Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_squid_spawn_egg"},{"id":"minecraft:glowstone","localizedName":"Glowstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glowstone"},{"id":"minecraft:glowstone_dust","localizedName":"Glowstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glowstone_dust"},{"id":"minecraft:goat_spawn_egg","localizedName":"Goat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.goat_spawn_egg"},{"id":"minecraft:gold_block","localizedName":"Block of Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_block"},{"id":"minecraft:gold_ingot","localizedName":"Gold Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_ingot"},{"id":"minecraft:gold_nugget","localizedName":"Gold Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_nugget"},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_ore"},{"id":"minecraft:golden_apple","localizedName":"Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_apple"},{"id":"minecraft:golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_axe"},{"id":"minecraft:golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_boots"},{"id":"minecraft:golden_carrot","localizedName":"Golden Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_carrot"},{"id":"minecraft:golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_chestplate"},{"id":"minecraft:golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_helmet"},{"id":"minecraft:golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_hoe"},{"id":"minecraft:golden_horse_armor","localizedName":"Golden Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_horse_armor"},{"id":"minecraft:golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_leggings"},{"id":"minecraft:golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_pickaxe"},{"id":"minecraft:golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_shovel"},{"id":"minecraft:golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_sword"},{"id":"minecraft:granite","localizedName":"Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite"},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_slab"},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_stairs"},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_wall"},{"id":"minecraft:grass","localizedName":"Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass"},{"id":"minecraft:grass_block","localizedName":"Grass Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass_block"},{"id":"minecraft:gravel","localizedName":"Gravel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gravel"},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.gray_banner"},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_bed"},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_candle"},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_carpet"},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete"},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete_powder"},{"id":"minecraft:gray_dye","localizedName":"Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gray_dye"},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_glazed_terracotta"},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_shulker_box"},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass"},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass_pane"},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_terracotta"},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_wool"},{"id":"minecraft:green_banner","localizedName":"Green Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.green_banner"},{"id":"minecraft:green_bed","localizedName":"Green Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_bed"},{"id":"minecraft:green_candle","localizedName":"Green Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_candle"},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_carpet"},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete"},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete_powder"},{"id":"minecraft:green_dye","localizedName":"Green Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.green_dye"},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_glazed_terracotta"},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_shulker_box"},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass"},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass_pane"},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_terracotta"},{"id":"minecraft:green_wool","localizedName":"Green Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_wool"},{"id":"minecraft:grindstone","localizedName":"Grindstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grindstone"},{"id":"minecraft:guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.guardian_spawn_egg"},{"id":"minecraft:gunpowder","localizedName":"Gunpowder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gunpowder"},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hanging_roots"},{"id":"minecraft:hay_block","localizedName":"Hay Bale","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hay_block"},{"id":"minecraft:heart_of_the_sea","localizedName":"Heart of the Sea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.heart_of_the_sea"},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate"},{"id":"minecraft:hoglin_spawn_egg","localizedName":"Hoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.hoglin_spawn_egg"},{"id":"minecraft:honey_block","localizedName":"Honey Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honey_block"},{"id":"minecraft:honey_bottle","localizedName":"Honey Bottle","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.honey_bottle"},{"id":"minecraft:honeycomb","localizedName":"Honeycomb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.honeycomb"},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honeycomb_block"},{"id":"minecraft:hopper","localizedName":"Hopper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hopper"},{"id":"minecraft:hopper_minecart","localizedName":"Minecart with Hopper","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.hopper_minecart"},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral"},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_block"},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_fan"},{"id":"minecraft:horse_spawn_egg","localizedName":"Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.horse_spawn_egg"},{"id":"minecraft:husk_spawn_egg","localizedName":"Husk Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.husk_spawn_egg"},{"id":"minecraft:ice","localizedName":"Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ice"},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks"},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cobblestone"},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cracked_stone_bricks"},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_deepslate"},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_mossy_stone_bricks"},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone"},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone_bricks"},{"id":"minecraft:ink_sac","localizedName":"Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ink_sac"},{"id":"minecraft:iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_axe"},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_bars"},{"id":"minecraft:iron_block","localizedName":"Block of Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_block"},{"id":"minecraft:iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_boots"},{"id":"minecraft:iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_chestplate"},{"id":"minecraft:iron_door","localizedName":"Iron Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_door"},{"id":"minecraft:iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_helmet"},{"id":"minecraft:iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_hoe"},{"id":"minecraft:iron_horse_armor","localizedName":"Iron Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_horse_armor"},{"id":"minecraft:iron_ingot","localizedName":"Iron Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_ingot"},{"id":"minecraft:iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_leggings"},{"id":"minecraft:iron_nugget","localizedName":"Iron Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_nugget"},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_ore"},{"id":"minecraft:iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_pickaxe"},{"id":"minecraft:iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_shovel"},{"id":"minecraft:iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_sword"},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_trapdoor"},{"id":"minecraft:item_frame","localizedName":"Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.item_frame"},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jack_o_lantern"},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jigsaw"},{"id":"minecraft:jukebox","localizedName":"Jukebox","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jukebox"},{"id":"minecraft:jungle_boat","localizedName":"Jungle Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_boat"},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_button"},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_door"},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence"},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence_gate"},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_leaves"},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_log"},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_planks"},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_pressure_plate"},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_sapling"},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_sign"},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_slab"},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_stairs"},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_trapdoor"},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_wood"},{"id":"minecraft:kelp","localizedName":"Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.kelp"},{"id":"minecraft:knowledge_book","localizedName":"Knowledge Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.knowledge_book"},{"id":"minecraft:ladder","localizedName":"Ladder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ladder"},{"id":"minecraft:lantern","localizedName":"Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lantern"},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_block"},{"id":"minecraft:lapis_lazuli","localizedName":"Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lapis_lazuli"},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_ore"},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_amethyst_bud"},{"id":"minecraft:large_fern","localizedName":"Large Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_fern"},{"id":"minecraft:lava_bucket","localizedName":"Lava Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lava_bucket"},{"id":"minecraft:lead","localizedName":"Lead","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lead"},{"id":"minecraft:leather","localizedName":"Leather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.leather"},{"id":"minecraft:leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_boots"},{"id":"minecraft:leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_chestplate"},{"id":"minecraft:leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_helmet"},{"id":"minecraft:leather_horse_armor","localizedName":"Leather Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_horse_armor"},{"id":"minecraft:leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_leggings"},{"id":"minecraft:lectern","localizedName":"Lectern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lectern"},{"id":"minecraft:lever","localizedName":"Lever","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lever"},{"id":"minecraft:light","localizedName":"Light","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light"},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_blue_banner"},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_bed"},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_candle"},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_carpet"},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete"},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete_powder"},{"id":"minecraft:light_blue_dye","localizedName":"Light Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_blue_dye"},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_glazed_terracotta"},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_shulker_box"},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass"},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass_pane"},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_terracotta"},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_wool"},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_gray_banner"},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_bed"},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_candle"},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_carpet"},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete"},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete_powder"},{"id":"minecraft:light_gray_dye","localizedName":"Light Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_gray_dye"},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_glazed_terracotta"},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_shulker_box"},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass"},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass_pane"},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_terracotta"},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_wool"},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_weighted_pressure_plate"},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lightning_rod"},{"id":"minecraft:lilac","localizedName":"Lilac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lilac"},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_of_the_valley"},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_pad"},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.lime_banner"},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_bed"},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_candle"},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_carpet"},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete"},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete_powder"},{"id":"minecraft:lime_dye","localizedName":"Lime Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lime_dye"},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_glazed_terracotta"},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_shulker_box"},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass"},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass_pane"},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_terracotta"},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_wool"},{"id":"minecraft:lingering_potion","localizedName":"Lingering Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lingering_potion.effect.water"},{"id":"minecraft:llama_spawn_egg","localizedName":"Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.llama_spawn_egg"},{"id":"minecraft:lodestone","localizedName":"Lodestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lodestone"},{"id":"minecraft:loom","localizedName":"Loom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.loom"},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.magenta_banner"},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_bed"},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_candle"},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_carpet"},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete"},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete_powder"},{"id":"minecraft:magenta_dye","localizedName":"Magenta Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magenta_dye"},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_glazed_terracotta"},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_shulker_box"},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass"},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass_pane"},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_terracotta"},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_wool"},{"id":"minecraft:magma_block","localizedName":"Magma Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magma_block"},{"id":"minecraft:magma_cream","localizedName":"Magma Cream","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cream"},{"id":"minecraft:magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cube_spawn_egg"},{"id":"minecraft:map","localizedName":"Empty Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.map"},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.medium_amethyst_bud"},{"id":"minecraft:melon","localizedName":"Melon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.melon"},{"id":"minecraft:melon_seeds","localizedName":"Melon Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_seeds"},{"id":"minecraft:melon_slice","localizedName":"Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_slice"},{"id":"minecraft:milk_bucket","localizedName":"Milk Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.milk_bucket"},{"id":"minecraft:minecart","localizedName":"Minecart","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.minecart"},{"id":"minecraft:mojang_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mojang_banner_pattern"},{"id":"minecraft:mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mooshroom_spawn_egg"},{"id":"minecraft:moss_block","localizedName":"Moss Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.moss_block"},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.moss_carpet"},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone"},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_slab"},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_stairs"},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_wall"},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_slab"},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_stairs"},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_wall"},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_bricks"},{"id":"minecraft:mule_spawn_egg","localizedName":"Mule Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mule_spawn_egg"},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mushroom_stem"},{"id":"minecraft:mushroom_stew","localizedName":"Mushroom Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mushroom_stew"},{"id":"minecraft:music_disc_11","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_11"},{"id":"minecraft:music_disc_13","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_13"},{"id":"minecraft:music_disc_blocks","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_blocks"},{"id":"minecraft:music_disc_cat","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_cat"},{"id":"minecraft:music_disc_chirp","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_chirp"},{"id":"minecraft:music_disc_far","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_far"},{"id":"minecraft:music_disc_mall","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mall"},{"id":"minecraft:music_disc_mellohi","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mellohi"},{"id":"minecraft:music_disc_pigstep","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_pigstep"},{"id":"minecraft:music_disc_stal","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_stal"},{"id":"minecraft:music_disc_strad","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_strad"},{"id":"minecraft:music_disc_wait","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_wait"},{"id":"minecraft:music_disc_ward","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_ward"},{"id":"minecraft:mutton","localizedName":"Raw Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mutton"},{"id":"minecraft:mycelium","localizedName":"Mycelium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mycelium"},{"id":"minecraft:name_tag","localizedName":"Name Tag","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.name_tag"},{"id":"minecraft:nautilus_shell","localizedName":"Nautilus Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nautilus_shell"},{"id":"minecraft:nether_brick","localizedName":"Nether Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_brick"},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_fence"},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_slab"},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_stairs"},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_wall"},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_bricks"},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_gold_ore"},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_quartz_ore"},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_sprouts"},{"id":"minecraft:nether_star","localizedName":"Nether Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_star"},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_wart"},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_wart_block"},{"id":"minecraft:netherite_axe","localizedName":"Netherite Axe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_axe"},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherite_block"},{"id":"minecraft:netherite_boots","localizedName":"Netherite Boots","maxDamage":481,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_boots"},{"id":"minecraft:netherite_chestplate","localizedName":"Netherite Chestplate","maxDamage":592,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_chestplate"},{"id":"minecraft:netherite_helmet","localizedName":"Netherite Helmet","maxDamage":407,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_helmet"},{"id":"minecraft:netherite_hoe","localizedName":"Netherite Hoe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_hoe"},{"id":"minecraft:netherite_ingot","localizedName":"Netherite Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_ingot"},{"id":"minecraft:netherite_leggings","localizedName":"Netherite Leggings","maxDamage":555,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_leggings"},{"id":"minecraft:netherite_pickaxe","localizedName":"Netherite Pickaxe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_pickaxe"},{"id":"minecraft:netherite_scrap","localizedName":"Netherite Scrap","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_scrap"},{"id":"minecraft:netherite_shovel","localizedName":"Netherite Shovel","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_shovel"},{"id":"minecraft:netherite_sword","localizedName":"Netherite Sword","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_sword"},{"id":"minecraft:netherrack","localizedName":"Netherrack","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherrack"},{"id":"minecraft:note_block","localizedName":"Note Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.note_block"},{"id":"minecraft:oak_boat","localizedName":"Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.oak_boat"},{"id":"minecraft:oak_button","localizedName":"Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_button"},{"id":"minecraft:oak_door","localizedName":"Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_door"},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence"},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence_gate"},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_leaves"},{"id":"minecraft:oak_log","localizedName":"Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_log"},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_planks"},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_pressure_plate"},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_sapling"},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.oak_sign"},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_slab"},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_stairs"},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_trapdoor"},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_wood"},{"id":"minecraft:observer","localizedName":"Observer","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.observer"},{"id":"minecraft:obsidian","localizedName":"Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.obsidian"},{"id":"minecraft:ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ocelot_spawn_egg"},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.orange_banner"},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_bed"},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_candle"},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_carpet"},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete"},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete_powder"},{"id":"minecraft:orange_dye","localizedName":"Orange Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.orange_dye"},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_glazed_terracotta"},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_shulker_box"},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass"},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass_pane"},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_terracotta"},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_tulip"},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_wool"},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxeye_daisy"},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper"},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper"},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_slab"},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_stairs"},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.packed_ice"},{"id":"minecraft:painting","localizedName":"Painting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.painting"},{"id":"minecraft:panda_spawn_egg","localizedName":"Panda Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.panda_spawn_egg"},{"id":"minecraft:paper","localizedName":"Paper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.paper"},{"id":"minecraft:parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.parrot_spawn_egg"},{"id":"minecraft:peony","localizedName":"Peony","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.peony"},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.petrified_oak_slab"},{"id":"minecraft:phantom_membrane","localizedName":"Phantom Membrane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_membrane"},{"id":"minecraft:phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_spawn_egg"},{"id":"minecraft:pig_spawn_egg","localizedName":"Pig Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pig_spawn_egg"},{"id":"minecraft:piglin_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.piglin_banner_pattern"},{"id":"minecraft:piglin_brute_spawn_egg","localizedName":"Piglin Brute Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_brute_spawn_egg"},{"id":"minecraft:piglin_spawn_egg","localizedName":"Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_spawn_egg"},{"id":"minecraft:pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pillager_spawn_egg"},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.pink_banner"},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_bed"},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_candle"},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_carpet"},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete"},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete_powder"},{"id":"minecraft:pink_dye","localizedName":"Pink Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pink_dye"},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_glazed_terracotta"},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_shulker_box"},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass"},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass_pane"},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_terracotta"},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_tulip"},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_wool"},{"id":"minecraft:piston","localizedName":"Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.piston"},{"id":"minecraft:player_head","localizedName":"Player Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.player_head"},{"id":"minecraft:podzol","localizedName":"Podzol","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.podzol"},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pointed_dripstone"},{"id":"minecraft:poisonous_potato","localizedName":"Poisonous Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.poisonous_potato"},{"id":"minecraft:polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.polar_bear_spawn_egg"},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite"},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_slab"},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_stairs"},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_basalt"},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone"},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_slab"},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_stairs"},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_wall"},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_bricks"},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_button"},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_pressure_plate"},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_slab"},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_stairs"},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_wall"},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate"},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_slab"},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_stairs"},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_wall"},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite"},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_slab"},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_stairs"},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite"},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_slab"},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_stairs"},{"id":"minecraft:popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.popped_chorus_fruit"},{"id":"minecraft:poppy","localizedName":"Poppy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.poppy"},{"id":"minecraft:porkchop","localizedName":"Raw Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.porkchop"},{"id":"minecraft:potato","localizedName":"Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.potato"},{"id":"minecraft:potion","localizedName":"Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.potion.effect.water"},{"id":"minecraft:powder_snow_bucket","localizedName":"Powder Snow Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.powder_snow_bucket"},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.powered_rail"},{"id":"minecraft:prismarine","localizedName":"Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine"},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_slab"},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_stairs"},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_bricks"},{"id":"minecraft:prismarine_crystals","localizedName":"Prismarine Crystals","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_crystals"},{"id":"minecraft:prismarine_shard","localizedName":"Prismarine Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_shard"},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_slab"},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_stairs"},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_wall"},{"id":"minecraft:pufferfish","localizedName":"Pufferfish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish"},{"id":"minecraft:pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.pufferfish_bucket"},{"id":"minecraft:pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish_spawn_egg"},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pumpkin"},{"id":"minecraft:pumpkin_pie","localizedName":"Pumpkin Pie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_pie"},{"id":"minecraft:pumpkin_seeds","localizedName":"Pumpkin Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_seeds"},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.purple_banner"},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_bed"},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_candle"},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_carpet"},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete"},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete_powder"},{"id":"minecraft:purple_dye","localizedName":"Purple Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.purple_dye"},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_glazed_terracotta"},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_shulker_box"},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass"},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass_pane"},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_terracotta"},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_wool"},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_block"},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_pillar"},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_slab"},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_stairs"},{"id":"minecraft:quartz","localizedName":"Nether Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.quartz"},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_block"},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_bricks"},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_pillar"},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_slab"},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_stairs"},{"id":"minecraft:rabbit","localizedName":"Raw Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit"},{"id":"minecraft:rabbit_foot","localizedName":"Rabbit\u0027s Foot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_foot"},{"id":"minecraft:rabbit_hide","localizedName":"Rabbit Hide","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_hide"},{"id":"minecraft:rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_spawn_egg"},{"id":"minecraft:rabbit_stew","localizedName":"Rabbit Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.rabbit_stew"},{"id":"minecraft:rail","localizedName":"Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rail"},{"id":"minecraft:ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ravager_spawn_egg"},{"id":"minecraft:raw_copper","localizedName":"Raw Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_copper"},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_copper_block"},{"id":"minecraft:raw_gold","localizedName":"Raw Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_gold"},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_gold_block"},{"id":"minecraft:raw_iron","localizedName":"Raw Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_iron"},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_iron_block"},{"id":"minecraft:red_banner","localizedName":"Red Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.red_banner"},{"id":"minecraft:red_bed","localizedName":"Red Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_bed"},{"id":"minecraft:red_candle","localizedName":"Red Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_candle"},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_carpet"},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete"},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete_powder"},{"id":"minecraft:red_dye","localizedName":"Red Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.red_dye"},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_glazed_terracotta"},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom"},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom_block"},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_slab"},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_stairs"},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_wall"},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_bricks"},{"id":"minecraft:red_sand","localizedName":"Red Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sand"},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone"},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_slab"},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_stairs"},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_wall"},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_shulker_box"},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass"},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass_pane"},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_terracotta"},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_tulip"},{"id":"minecraft:red_wool","localizedName":"Red Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_wool"},{"id":"minecraft:redstone","localizedName":"Redstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.redstone"},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_block"},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_lamp"},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_ore"},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_torch"},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeater"},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeating_command_block"},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.respawn_anchor"},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rooted_dirt"},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rose_bush"},{"id":"minecraft:rotten_flesh","localizedName":"Rotten Flesh","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rotten_flesh"},{"id":"minecraft:saddle","localizedName":"Saddle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.saddle"},{"id":"minecraft:salmon","localizedName":"Raw Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon"},{"id":"minecraft:salmon_bucket","localizedName":"Bucket of Salmon","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.salmon_bucket"},{"id":"minecraft:salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon_spawn_egg"},{"id":"minecraft:sand","localizedName":"Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sand"},{"id":"minecraft:sandstone","localizedName":"Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone"},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_slab"},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_stairs"},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_wall"},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.scaffolding"},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_sensor"},{"id":"minecraft:scute","localizedName":"Scute","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.scute"},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_lantern"},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_pickle"},{"id":"minecraft:seagrass","localizedName":"Seagrass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.seagrass"},{"id":"minecraft:shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1,"unlocalizedName":"item.minecraft.shears"},{"id":"minecraft:sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sheep_spawn_egg"},{"id":"minecraft:shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1,"unlocalizedName":"item.minecraft.shield"},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.shroomlight"},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.shulker_box"},{"id":"minecraft:shulker_shell","localizedName":"Shulker Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_shell"},{"id":"minecraft:shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_spawn_egg"},{"id":"minecraft:silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.silverfish_spawn_egg"},{"id":"minecraft:skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg"},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.skeleton_skull"},{"id":"minecraft:skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_spawn_egg"},{"id":"minecraft:skull_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.skull_banner_pattern"},{"id":"minecraft:slime_ball","localizedName":"Slimeball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_ball"},{"id":"minecraft:slime_block","localizedName":"Slime Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.slime_block"},{"id":"minecraft:slime_spawn_egg","localizedName":"Slime Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_spawn_egg"},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.small_amethyst_bud"},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.small_dripleaf"},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smithing_table"},{"id":"minecraft:smoker","localizedName":"Smoker","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smoker"},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_basalt"},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz"},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_slab"},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_stairs"},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone"},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_slab"},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs"},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone"},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_slab"},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_stairs"},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone"},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone_slab"},{"id":"minecraft:snow","localizedName":"Snow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow"},{"id":"minecraft:snow_block","localizedName":"Snow Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow_block"},{"id":"minecraft:snowball","localizedName":"Snowball","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.snowball"},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_campfire"},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_lantern"},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_sand"},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_soil"},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_torch"},{"id":"minecraft:spawner","localizedName":"Spawner","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spawner"},{"id":"minecraft:spectral_arrow","localizedName":"Spectral Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spectral_arrow"},{"id":"minecraft:spider_eye","localizedName":"Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_eye"},{"id":"minecraft:spider_spawn_egg","localizedName":"Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_spawn_egg"},{"id":"minecraft:splash_potion","localizedName":"Splash Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.splash_potion.effect.water"},{"id":"minecraft:sponge","localizedName":"Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sponge"},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spore_blossom"},{"id":"minecraft:spruce_boat","localizedName":"Spruce Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_boat"},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_button"},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_door"},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence"},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence_gate"},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_leaves"},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_log"},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_planks"},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_pressure_plate"},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_sapling"},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_sign"},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_slab"},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_stairs"},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_trapdoor"},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_wood"},{"id":"minecraft:spyglass","localizedName":"Spyglass","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spyglass"},{"id":"minecraft:squid_spawn_egg","localizedName":"Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.squid_spawn_egg"},{"id":"minecraft:stick","localizedName":"Stick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stick"},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sticky_piston"},{"id":"minecraft:stone","localizedName":"Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone"},{"id":"minecraft:stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_axe"},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_slab"},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_stairs"},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_wall"},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_bricks"},{"id":"minecraft:stone_button","localizedName":"Stone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_button"},{"id":"minecraft:stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_hoe"},{"id":"minecraft:stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_pickaxe"},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_pressure_plate"},{"id":"minecraft:stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_shovel"},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_slab"},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_stairs"},{"id":"minecraft:stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_sword"},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stonecutter"},{"id":"minecraft:stray_spawn_egg","localizedName":"Stray Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stray_spawn_egg"},{"id":"minecraft:strider_spawn_egg","localizedName":"Strider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.strider_spawn_egg"},{"id":"minecraft:string","localizedName":"String","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.string"},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_log"},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_wood"},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_log"},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_wood"},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_hyphae"},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_stem"},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_log"},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_wood"},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_log"},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_wood"},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_log"},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_wood"},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_log"},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_wood"},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_hyphae"},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_stem"},{"id":"minecraft:structure_block","localizedName":"Structure Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_block"},{"id":"minecraft:structure_void","localizedName":"Structure Void","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_void"},{"id":"minecraft:sugar","localizedName":"Sugar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sugar"},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sugar_cane"},{"id":"minecraft:sunflower","localizedName":"Sunflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sunflower"},{"id":"minecraft:suspicious_stew","localizedName":"Suspicious Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.suspicious_stew"},{"id":"minecraft:sweet_berries","localizedName":"Sweet Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sweet_berries"},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tall_grass"},{"id":"minecraft:target","localizedName":"Target","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.target"},{"id":"minecraft:terracotta","localizedName":"Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.terracotta"},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tinted_glass"},{"id":"minecraft:tipped_arrow","localizedName":"Arrow of Poison","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tipped_arrow.effect.poison"},{"id":"minecraft:tnt","localizedName":"TNT","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tnt"},{"id":"minecraft:tnt_minecart","localizedName":"Minecart with TNT","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tnt_minecart"},{"id":"minecraft:torch","localizedName":"Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.torch"},{"id":"minecraft:totem_of_undying","localizedName":"Totem of Undying","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.totem_of_undying"},{"id":"minecraft:trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.trader_llama_spawn_egg"},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.trapped_chest"},{"id":"minecraft:trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.trident"},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tripwire_hook"},{"id":"minecraft:tropical_fish","localizedName":"Tropical Fish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish"},{"id":"minecraft:tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tropical_fish_bucket"},{"id":"minecraft:tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish_spawn_egg"},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral"},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_block"},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_fan"},{"id":"minecraft:tuff","localizedName":"Tuff","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tuff"},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.turtle_egg"},{"id":"minecraft:turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1,"unlocalizedName":"item.minecraft.turtle_helmet"},{"id":"minecraft:turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_spawn_egg"},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.twisting_vines"},{"id":"minecraft:vex_spawn_egg","localizedName":"Vex Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vex_spawn_egg"},{"id":"minecraft:villager_spawn_egg","localizedName":"Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.villager_spawn_egg"},{"id":"minecraft:vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vindicator_spawn_egg"},{"id":"minecraft:vine","localizedName":"Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.vine"},{"id":"minecraft:wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wandering_trader_spawn_egg"},{"id":"minecraft:warped_button","localizedName":"Warped Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_button"},{"id":"minecraft:warped_door","localizedName":"Warped Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_door"},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence"},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence_gate"},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fungus"},{"id":"minecraft:warped_fungus_on_a_stick","localizedName":"Warped Fungus on a Stick","maxDamage":100,"maxStackSize":1,"unlocalizedName":"item.minecraft.warped_fungus_on_a_stick"},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_hyphae"},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_nylium"},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_planks"},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_pressure_plate"},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_roots"},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.warped_sign"},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_slab"},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stairs"},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stem"},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_trapdoor"},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_wart_block"},{"id":"minecraft:water_bucket","localizedName":"Water Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.water_bucket"},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_block"},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper"},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_slab"},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_stairs"},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper"},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper"},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_slab"},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_stairs"},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper"},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper"},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_slab"},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_stairs"},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper"},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper"},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_slab"},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_stairs"},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper"},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper"},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_slab"},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_stairs"},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weeping_vines"},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wet_sponge"},{"id":"minecraft:wheat","localizedName":"Wheat","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat"},{"id":"minecraft:wheat_seeds","localizedName":"Wheat Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat_seeds"},{"id":"minecraft:white_banner","localizedName":"White Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.white_banner"},{"id":"minecraft:white_bed","localizedName":"White Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_bed"},{"id":"minecraft:white_candle","localizedName":"White Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_candle"},{"id":"minecraft:white_carpet","localizedName":"White Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_carpet"},{"id":"minecraft:white_concrete","localizedName":"White Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete"},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete_powder"},{"id":"minecraft:white_dye","localizedName":"White Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.white_dye"},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_glazed_terracotta"},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_shulker_box"},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass"},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass_pane"},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_terracotta"},{"id":"minecraft:white_tulip","localizedName":"White Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_tulip"},{"id":"minecraft:white_wool","localizedName":"White Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_wool"},{"id":"minecraft:witch_spawn_egg","localizedName":"Witch Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.witch_spawn_egg"},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_rose"},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_skeleton_skull"},{"id":"minecraft:wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg"},{"id":"minecraft:wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wolf_spawn_egg"},{"id":"minecraft:wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_axe"},{"id":"minecraft:wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_hoe"},{"id":"minecraft:wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_pickaxe"},{"id":"minecraft:wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_shovel"},{"id":"minecraft:wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_sword"},{"id":"minecraft:writable_book","localizedName":"Book and Quill","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.writable_book"},{"id":"minecraft:written_book","localizedName":"Written Book","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.written_book"},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.yellow_banner"},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_bed"},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_candle"},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_carpet"},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete"},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete_powder"},{"id":"minecraft:yellow_dye","localizedName":"Yellow Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.yellow_dye"},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_glazed_terracotta"},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_shulker_box"},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass"},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass_pane"},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_terracotta"},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_wool"},{"id":"minecraft:zoglin_spawn_egg","localizedName":"Zoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zoglin_spawn_egg"},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.zombie_head"},{"id":"minecraft:zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_horse_spawn_egg"},{"id":"minecraft:zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_spawn_egg"},{"id":"minecraft:zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_villager_spawn_egg"},{"id":"minecraft:zombified_piglin_spawn_egg","localizedName":"Zombified Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombified_piglin_spawn_egg"}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/items.119.json b/src/main/resources/com/sk89q/worldedit/world/registry/items.119.json new file mode 100644 index 0000000..4166656 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/items.119.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_boat","localizedName":"Acacia Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_boat"},{"id":"minecraft:acacia_button","localizedName":"Acacia Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_button"},{"id":"minecraft:acacia_chest_boat","localizedName":"Acacia Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_chest_boat"},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_door"},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence"},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence_gate"},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_leaves"},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_log"},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_planks"},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_pressure_plate"},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_sapling"},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_sign"},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_slab"},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_stairs"},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_trapdoor"},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_wood"},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.activator_rail"},{"id":"minecraft:air","localizedName":"Air","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.air"},{"id":"minecraft:allay_spawn_egg","localizedName":"Allay Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.allay_spawn_egg"},{"id":"minecraft:allium","localizedName":"Allium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.allium"},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_block"},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_cluster"},{"id":"minecraft:amethyst_shard","localizedName":"Amethyst Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.amethyst_shard"},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ancient_debris"},{"id":"minecraft:andesite","localizedName":"Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite"},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_slab"},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_stairs"},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_wall"},{"id":"minecraft:anvil","localizedName":"Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.anvil"},{"id":"minecraft:apple","localizedName":"Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.apple"},{"id":"minecraft:armor_stand","localizedName":"Armor Stand","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.armor_stand"},{"id":"minecraft:arrow","localizedName":"Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.arrow"},{"id":"minecraft:axolotl_bucket","localizedName":"Bucket of Axolotl","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.axolotl_bucket"},{"id":"minecraft:axolotl_spawn_egg","localizedName":"Axolotl Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.axolotl_spawn_egg"},{"id":"minecraft:azalea","localizedName":"Azalea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azalea"},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azalea_leaves"},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azure_bluet"},{"id":"minecraft:baked_potato","localizedName":"Baked Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.baked_potato"},{"id":"minecraft:bamboo","localizedName":"Bamboo","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo"},{"id":"minecraft:barrel","localizedName":"Barrel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrel"},{"id":"minecraft:barrier","localizedName":"Barrier","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrier"},{"id":"minecraft:basalt","localizedName":"Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.basalt"},{"id":"minecraft:bat_spawn_egg","localizedName":"Bat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bat_spawn_egg"},{"id":"minecraft:beacon","localizedName":"Beacon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beacon"},{"id":"minecraft:bedrock","localizedName":"Bedrock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bedrock"},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bee_nest"},{"id":"minecraft:bee_spawn_egg","localizedName":"Bee Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bee_spawn_egg"},{"id":"minecraft:beef","localizedName":"Raw Beef","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beef"},{"id":"minecraft:beehive","localizedName":"Beehive","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beehive"},{"id":"minecraft:beetroot","localizedName":"Beetroot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot"},{"id":"minecraft:beetroot_seeds","localizedName":"Beetroot Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot_seeds"},{"id":"minecraft:beetroot_soup","localizedName":"Beetroot Soup","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.beetroot_soup"},{"id":"minecraft:bell","localizedName":"Bell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bell"},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.big_dripleaf"},{"id":"minecraft:birch_boat","localizedName":"Birch Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.birch_boat"},{"id":"minecraft:birch_button","localizedName":"Birch Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_button"},{"id":"minecraft:birch_chest_boat","localizedName":"Birch Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.birch_chest_boat"},{"id":"minecraft:birch_door","localizedName":"Birch Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_door"},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence"},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence_gate"},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_leaves"},{"id":"minecraft:birch_log","localizedName":"Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_log"},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_planks"},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_pressure_plate"},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_sapling"},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.birch_sign"},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_slab"},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_stairs"},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_trapdoor"},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_wood"},{"id":"minecraft:black_banner","localizedName":"Black Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.black_banner"},{"id":"minecraft:black_bed","localizedName":"Black Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_bed"},{"id":"minecraft:black_candle","localizedName":"Black Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_candle"},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_carpet"},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete"},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete_powder"},{"id":"minecraft:black_dye","localizedName":"Black Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.black_dye"},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_glazed_terracotta"},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_shulker_box"},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass"},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass_pane"},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_terracotta"},{"id":"minecraft:black_wool","localizedName":"Black Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_wool"},{"id":"minecraft:blackstone","localizedName":"Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone"},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_slab"},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_stairs"},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_wall"},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blast_furnace"},{"id":"minecraft:blaze_powder","localizedName":"Blaze Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_powder"},{"id":"minecraft:blaze_rod","localizedName":"Blaze Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_rod"},{"id":"minecraft:blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_spawn_egg"},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.blue_banner"},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_bed"},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_candle"},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_carpet"},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete"},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete_powder"},{"id":"minecraft:blue_dye","localizedName":"Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blue_dye"},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_glazed_terracotta"},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_ice"},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_orchid"},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_shulker_box"},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass"},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass_pane"},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_terracotta"},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_wool"},{"id":"minecraft:bone","localizedName":"Bone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone"},{"id":"minecraft:bone_block","localizedName":"Bone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bone_block"},{"id":"minecraft:bone_meal","localizedName":"Bone Meal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone_meal"},{"id":"minecraft:book","localizedName":"Book","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.book"},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bookshelf"},{"id":"minecraft:bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1,"unlocalizedName":"item.minecraft.bow"},{"id":"minecraft:bowl","localizedName":"Bowl","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bowl"},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral"},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_block"},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_fan"},{"id":"minecraft:bread","localizedName":"Bread","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bread"},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brewing_stand"},{"id":"minecraft:brick","localizedName":"Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brick"},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_slab"},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_stairs"},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_wall"},{"id":"minecraft:bricks","localizedName":"Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bricks"},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.brown_banner"},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_bed"},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_candle"},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_carpet"},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete"},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete_powder"},{"id":"minecraft:brown_dye","localizedName":"Brown Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brown_dye"},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_glazed_terracotta"},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom"},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom_block"},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_shulker_box"},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass"},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass_pane"},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_terracotta"},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_wool"},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral"},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_block"},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_fan"},{"id":"minecraft:bucket","localizedName":"Bucket","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.bucket"},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.budding_amethyst"},{"id":"minecraft:bundle","localizedName":"Bundle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.bundle"},{"id":"minecraft:cactus","localizedName":"Cactus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cactus"},{"id":"minecraft:cake","localizedName":"Cake","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cake"},{"id":"minecraft:calcite","localizedName":"Calcite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.calcite"},{"id":"minecraft:campfire","localizedName":"Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.campfire"},{"id":"minecraft:candle","localizedName":"Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.candle"},{"id":"minecraft:carrot","localizedName":"Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.carrot"},{"id":"minecraft:carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1,"unlocalizedName":"item.minecraft.carrot_on_a_stick"},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cartography_table"},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.carved_pumpkin"},{"id":"minecraft:cat_spawn_egg","localizedName":"Cat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cat_spawn_egg"},{"id":"minecraft:cauldron","localizedName":"Cauldron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cauldron"},{"id":"minecraft:cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cave_spider_spawn_egg"},{"id":"minecraft:chain","localizedName":"Chain","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain"},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain_command_block"},{"id":"minecraft:chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_boots"},{"id":"minecraft:chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_chestplate"},{"id":"minecraft:chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_helmet"},{"id":"minecraft:chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_leggings"},{"id":"minecraft:charcoal","localizedName":"Charcoal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.charcoal"},{"id":"minecraft:chest","localizedName":"Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chest"},{"id":"minecraft:chest_minecart","localizedName":"Minecart with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.chest_minecart"},{"id":"minecraft:chicken","localizedName":"Raw Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken"},{"id":"minecraft:chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken_spawn_egg"},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chipped_anvil"},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_deepslate"},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_nether_bricks"},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_polished_blackstone"},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_quartz_block"},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_red_sandstone"},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_sandstone"},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_stone_bricks"},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_flower"},{"id":"minecraft:chorus_fruit","localizedName":"Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chorus_fruit"},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_plant"},{"id":"minecraft:clay","localizedName":"Clay","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.clay"},{"id":"minecraft:clay_ball","localizedName":"Clay Ball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clay_ball"},{"id":"minecraft:clock","localizedName":"Clock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clock"},{"id":"minecraft:coal","localizedName":"Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.coal"},{"id":"minecraft:coal_block","localizedName":"Block of Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_block"},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_ore"},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coarse_dirt"},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate"},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_slab"},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_stairs"},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_wall"},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone"},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_slab"},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_stairs"},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_wall"},{"id":"minecraft:cobweb","localizedName":"Cobweb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobweb"},{"id":"minecraft:cocoa_beans","localizedName":"Cocoa Beans","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cocoa_beans"},{"id":"minecraft:cod","localizedName":"Raw Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod"},{"id":"minecraft:cod_bucket","localizedName":"Bucket of Cod","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.cod_bucket"},{"id":"minecraft:cod_spawn_egg","localizedName":"Cod Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod_spawn_egg"},{"id":"minecraft:command_block","localizedName":"Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.command_block"},{"id":"minecraft:command_block_minecart","localizedName":"Minecart with Command Block","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.command_block_minecart"},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.comparator"},{"id":"minecraft:compass","localizedName":"Compass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.compass"},{"id":"minecraft:composter","localizedName":"Composter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.composter"},{"id":"minecraft:conduit","localizedName":"Conduit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.conduit"},{"id":"minecraft:cooked_beef","localizedName":"Steak","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_beef"},{"id":"minecraft:cooked_chicken","localizedName":"Cooked Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_chicken"},{"id":"minecraft:cooked_cod","localizedName":"Cooked Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_cod"},{"id":"minecraft:cooked_mutton","localizedName":"Cooked Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_mutton"},{"id":"minecraft:cooked_porkchop","localizedName":"Cooked Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_porkchop"},{"id":"minecraft:cooked_rabbit","localizedName":"Cooked Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_rabbit"},{"id":"minecraft:cooked_salmon","localizedName":"Cooked Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_salmon"},{"id":"minecraft:cookie","localizedName":"Cookie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cookie"},{"id":"minecraft:copper_block","localizedName":"Block of Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.copper_block"},{"id":"minecraft:copper_ingot","localizedName":"Copper Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.copper_ingot"},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.copper_ore"},{"id":"minecraft:cornflower","localizedName":"Cornflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cornflower"},{"id":"minecraft:cow_spawn_egg","localizedName":"Cow Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cow_spawn_egg"},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_bricks"},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_tiles"},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_nether_bricks"},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_polished_blackstone_bricks"},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_stone_bricks"},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crafting_table"},{"id":"minecraft:creeper_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.creeper_banner_pattern"},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.creeper_head"},{"id":"minecraft:creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.creeper_spawn_egg"},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_button"},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_door"},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence"},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence_gate"},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fungus"},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_hyphae"},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_nylium"},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_planks"},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_pressure_plate"},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_roots"},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_sign"},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_slab"},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stairs"},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stem"},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_trapdoor"},{"id":"minecraft:crossbow","localizedName":"Crossbow","maxDamage":465,"maxStackSize":1,"unlocalizedName":"item.minecraft.crossbow"},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crying_obsidian"},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper"},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_slab"},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_stairs"},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone"},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone_slab"},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone"},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone_slab"},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.cyan_banner"},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_bed"},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_candle"},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_carpet"},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete"},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete_powder"},{"id":"minecraft:cyan_dye","localizedName":"Cyan Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cyan_dye"},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_glazed_terracotta"},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_shulker_box"},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass"},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass_pane"},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_terracotta"},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_wool"},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.damaged_anvil"},{"id":"minecraft:dandelion","localizedName":"Dandelion","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dandelion"},{"id":"minecraft:dark_oak_boat","localizedName":"Dark Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_boat"},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_button"},{"id":"minecraft:dark_oak_chest_boat","localizedName":"Dark Oak Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_chest_boat"},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_door"},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence"},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence_gate"},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_leaves"},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_log"},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_planks"},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_pressure_plate"},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_sapling"},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_sign"},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_slab"},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_stairs"},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_trapdoor"},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_wood"},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine"},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_slab"},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_stairs"},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.daylight_detector"},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral"},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_block"},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_fan"},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral"},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_block"},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_fan"},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bush"},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral"},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_block"},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_fan"},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral"},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_block"},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_fan"},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral"},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_block"},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_fan"},{"id":"minecraft:debug_stick","localizedName":"Debug Stick","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.debug_stick"},{"id":"minecraft:deepslate","localizedName":"Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate"},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_slab"},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_stairs"},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_wall"},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_bricks"},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_coal_ore"},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_copper_ore"},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_diamond_ore"},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_emerald_ore"},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_gold_ore"},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_iron_ore"},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_lapis_ore"},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_redstone_ore"},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_slab"},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_stairs"},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_wall"},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tiles"},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.detector_rail"},{"id":"minecraft:diamond","localizedName":"Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.diamond"},{"id":"minecraft:diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_axe"},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_block"},{"id":"minecraft:diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_boots"},{"id":"minecraft:diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_chestplate"},{"id":"minecraft:diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_helmet"},{"id":"minecraft:diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_hoe"},{"id":"minecraft:diamond_horse_armor","localizedName":"Diamond Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_horse_armor"},{"id":"minecraft:diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_leggings"},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_ore"},{"id":"minecraft:diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_pickaxe"},{"id":"minecraft:diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_shovel"},{"id":"minecraft:diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_sword"},{"id":"minecraft:diorite","localizedName":"Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite"},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_slab"},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_stairs"},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_wall"},{"id":"minecraft:dirt","localizedName":"Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt"},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt_path"},{"id":"minecraft:disc_fragment_5","localizedName":"Disc Fragment","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.disc_fragment_5"},{"id":"minecraft:dispenser","localizedName":"Dispenser","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dispenser"},{"id":"minecraft:dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dolphin_spawn_egg"},{"id":"minecraft:donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.donkey_spawn_egg"},{"id":"minecraft:dragon_breath","localizedName":"Dragon\u0027s Breath","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dragon_breath"},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_egg"},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_head"},{"id":"minecraft:dried_kelp","localizedName":"Dried Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dried_kelp"},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dried_kelp_block"},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dripstone_block"},{"id":"minecraft:dropper","localizedName":"Dropper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dropper"},{"id":"minecraft:drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.drowned_spawn_egg"},{"id":"minecraft:echo_shard","localizedName":"Echo Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.echo_shard"},{"id":"minecraft:egg","localizedName":"Egg","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.egg"},{"id":"minecraft:elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.elder_guardian_spawn_egg"},{"id":"minecraft:elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1,"unlocalizedName":"item.minecraft.elytra"},{"id":"minecraft:emerald","localizedName":"Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.emerald"},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_block"},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_ore"},{"id":"minecraft:enchanted_book","localizedName":"Enchanted Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.enchanted_book"},{"id":"minecraft:enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enchanted_golden_apple"},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.enchanting_table"},{"id":"minecraft:end_crystal","localizedName":"End Crystal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.end_crystal"},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_portal_frame"},{"id":"minecraft:end_rod","localizedName":"End Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_rod"},{"id":"minecraft:end_stone","localizedName":"End Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone"},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_slab"},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_stairs"},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_wall"},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_bricks"},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ender_chest"},{"id":"minecraft:ender_eye","localizedName":"Eye of Ender","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ender_eye"},{"id":"minecraft:ender_pearl","localizedName":"Ender Pearl","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.ender_pearl"},{"id":"minecraft:enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enderman_spawn_egg"},{"id":"minecraft:endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.endermite_spawn_egg"},{"id":"minecraft:evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.evoker_spawn_egg"},{"id":"minecraft:experience_bottle","localizedName":"Bottle o\u0027 Enchanting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.experience_bottle"},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper"},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper"},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_slab"},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_stairs"},{"id":"minecraft:farmland","localizedName":"Farmland","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.farmland"},{"id":"minecraft:feather","localizedName":"Feather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.feather"},{"id":"minecraft:fermented_spider_eye","localizedName":"Fermented Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fermented_spider_eye"},{"id":"minecraft:fern","localizedName":"Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fern"},{"id":"minecraft:filled_map","localizedName":"Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.filled_map"},{"id":"minecraft:fire_charge","localizedName":"Fire Charge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fire_charge"},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral"},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_block"},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_fan"},{"id":"minecraft:firework_rocket","localizedName":"Firework Rocket","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_rocket"},{"id":"minecraft:firework_star","localizedName":"Firework Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_star"},{"id":"minecraft:fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.fishing_rod"},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fletching_table"},{"id":"minecraft:flint","localizedName":"Flint","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.flint"},{"id":"minecraft:flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.flint_and_steel"},{"id":"minecraft:flower_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.flower_banner_pattern"},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flower_pot"},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea"},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea_leaves"},{"id":"minecraft:fox_spawn_egg","localizedName":"Fox Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fox_spawn_egg"},{"id":"minecraft:frog_spawn_egg","localizedName":"Frog Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.frog_spawn_egg"},{"id":"minecraft:frogspawn","localizedName":"Frogspawn","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.frogspawn"},{"id":"minecraft:furnace","localizedName":"Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.furnace"},{"id":"minecraft:furnace_minecart","localizedName":"Minecart with Furnace","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.furnace_minecart"},{"id":"minecraft:ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_spawn_egg"},{"id":"minecraft:ghast_tear","localizedName":"Ghast Tear","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_tear"},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gilded_blackstone"},{"id":"minecraft:glass","localizedName":"Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass"},{"id":"minecraft:glass_bottle","localizedName":"Glass Bottle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glass_bottle"},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass_pane"},{"id":"minecraft:glistering_melon_slice","localizedName":"Glistering Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glistering_melon_slice"},{"id":"minecraft:globe_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.globe_banner_pattern"},{"id":"minecraft:glow_berries","localizedName":"Glow Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_berries"},{"id":"minecraft:glow_ink_sac","localizedName":"Glow Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_ink_sac"},{"id":"minecraft:glow_item_frame","localizedName":"Glow Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_item_frame"},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glow_lichen"},{"id":"minecraft:glow_squid_spawn_egg","localizedName":"Glow Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_squid_spawn_egg"},{"id":"minecraft:glowstone","localizedName":"Glowstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glowstone"},{"id":"minecraft:glowstone_dust","localizedName":"Glowstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glowstone_dust"},{"id":"minecraft:goat_horn","localizedName":"Goat Horn","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.goat_horn"},{"id":"minecraft:goat_spawn_egg","localizedName":"Goat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.goat_spawn_egg"},{"id":"minecraft:gold_block","localizedName":"Block of Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_block"},{"id":"minecraft:gold_ingot","localizedName":"Gold Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_ingot"},{"id":"minecraft:gold_nugget","localizedName":"Gold Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_nugget"},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_ore"},{"id":"minecraft:golden_apple","localizedName":"Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_apple"},{"id":"minecraft:golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_axe"},{"id":"minecraft:golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_boots"},{"id":"minecraft:golden_carrot","localizedName":"Golden Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_carrot"},{"id":"minecraft:golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_chestplate"},{"id":"minecraft:golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_helmet"},{"id":"minecraft:golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_hoe"},{"id":"minecraft:golden_horse_armor","localizedName":"Golden Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_horse_armor"},{"id":"minecraft:golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_leggings"},{"id":"minecraft:golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_pickaxe"},{"id":"minecraft:golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_shovel"},{"id":"minecraft:golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_sword"},{"id":"minecraft:granite","localizedName":"Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite"},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_slab"},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_stairs"},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_wall"},{"id":"minecraft:grass","localizedName":"Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass"},{"id":"minecraft:grass_block","localizedName":"Grass Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass_block"},{"id":"minecraft:gravel","localizedName":"Gravel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gravel"},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.gray_banner"},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_bed"},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_candle"},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_carpet"},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete"},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete_powder"},{"id":"minecraft:gray_dye","localizedName":"Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gray_dye"},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_glazed_terracotta"},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_shulker_box"},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass"},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass_pane"},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_terracotta"},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_wool"},{"id":"minecraft:green_banner","localizedName":"Green Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.green_banner"},{"id":"minecraft:green_bed","localizedName":"Green Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_bed"},{"id":"minecraft:green_candle","localizedName":"Green Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_candle"},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_carpet"},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete"},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete_powder"},{"id":"minecraft:green_dye","localizedName":"Green Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.green_dye"},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_glazed_terracotta"},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_shulker_box"},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass"},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass_pane"},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_terracotta"},{"id":"minecraft:green_wool","localizedName":"Green Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_wool"},{"id":"minecraft:grindstone","localizedName":"Grindstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grindstone"},{"id":"minecraft:guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.guardian_spawn_egg"},{"id":"minecraft:gunpowder","localizedName":"Gunpowder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gunpowder"},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hanging_roots"},{"id":"minecraft:hay_block","localizedName":"Hay Bale","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hay_block"},{"id":"minecraft:heart_of_the_sea","localizedName":"Heart of the Sea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.heart_of_the_sea"},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate"},{"id":"minecraft:hoglin_spawn_egg","localizedName":"Hoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.hoglin_spawn_egg"},{"id":"minecraft:honey_block","localizedName":"Honey Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honey_block"},{"id":"minecraft:honey_bottle","localizedName":"Honey Bottle","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.honey_bottle"},{"id":"minecraft:honeycomb","localizedName":"Honeycomb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.honeycomb"},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honeycomb_block"},{"id":"minecraft:hopper","localizedName":"Hopper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hopper"},{"id":"minecraft:hopper_minecart","localizedName":"Minecart with Hopper","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.hopper_minecart"},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral"},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_block"},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_fan"},{"id":"minecraft:horse_spawn_egg","localizedName":"Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.horse_spawn_egg"},{"id":"minecraft:husk_spawn_egg","localizedName":"Husk Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.husk_spawn_egg"},{"id":"minecraft:ice","localizedName":"Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ice"},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks"},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cobblestone"},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cracked_stone_bricks"},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_deepslate"},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_mossy_stone_bricks"},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone"},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone_bricks"},{"id":"minecraft:ink_sac","localizedName":"Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ink_sac"},{"id":"minecraft:iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_axe"},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_bars"},{"id":"minecraft:iron_block","localizedName":"Block of Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_block"},{"id":"minecraft:iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_boots"},{"id":"minecraft:iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_chestplate"},{"id":"minecraft:iron_door","localizedName":"Iron Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_door"},{"id":"minecraft:iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_helmet"},{"id":"minecraft:iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_hoe"},{"id":"minecraft:iron_horse_armor","localizedName":"Iron Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_horse_armor"},{"id":"minecraft:iron_ingot","localizedName":"Iron Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_ingot"},{"id":"minecraft:iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_leggings"},{"id":"minecraft:iron_nugget","localizedName":"Iron Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_nugget"},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_ore"},{"id":"minecraft:iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_pickaxe"},{"id":"minecraft:iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_shovel"},{"id":"minecraft:iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_sword"},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_trapdoor"},{"id":"minecraft:item_frame","localizedName":"Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.item_frame"},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jack_o_lantern"},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jigsaw"},{"id":"minecraft:jukebox","localizedName":"Jukebox","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jukebox"},{"id":"minecraft:jungle_boat","localizedName":"Jungle Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_boat"},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_button"},{"id":"minecraft:jungle_chest_boat","localizedName":"Jungle Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_chest_boat"},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_door"},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence"},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence_gate"},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_leaves"},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_log"},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_planks"},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_pressure_plate"},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_sapling"},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_sign"},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_slab"},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_stairs"},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_trapdoor"},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_wood"},{"id":"minecraft:kelp","localizedName":"Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.kelp"},{"id":"minecraft:knowledge_book","localizedName":"Knowledge Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.knowledge_book"},{"id":"minecraft:ladder","localizedName":"Ladder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ladder"},{"id":"minecraft:lantern","localizedName":"Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lantern"},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_block"},{"id":"minecraft:lapis_lazuli","localizedName":"Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lapis_lazuli"},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_ore"},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_amethyst_bud"},{"id":"minecraft:large_fern","localizedName":"Large Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_fern"},{"id":"minecraft:lava_bucket","localizedName":"Lava Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lava_bucket"},{"id":"minecraft:lead","localizedName":"Lead","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lead"},{"id":"minecraft:leather","localizedName":"Leather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.leather"},{"id":"minecraft:leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_boots"},{"id":"minecraft:leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_chestplate"},{"id":"minecraft:leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_helmet"},{"id":"minecraft:leather_horse_armor","localizedName":"Leather Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_horse_armor"},{"id":"minecraft:leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_leggings"},{"id":"minecraft:lectern","localizedName":"Lectern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lectern"},{"id":"minecraft:lever","localizedName":"Lever","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lever"},{"id":"minecraft:light","localizedName":"Light","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light"},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_blue_banner"},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_bed"},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_candle"},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_carpet"},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete"},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete_powder"},{"id":"minecraft:light_blue_dye","localizedName":"Light Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_blue_dye"},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_glazed_terracotta"},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_shulker_box"},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass"},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass_pane"},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_terracotta"},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_wool"},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_gray_banner"},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_bed"},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_candle"},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_carpet"},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete"},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete_powder"},{"id":"minecraft:light_gray_dye","localizedName":"Light Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_gray_dye"},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_glazed_terracotta"},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_shulker_box"},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass"},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass_pane"},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_terracotta"},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_wool"},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_weighted_pressure_plate"},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lightning_rod"},{"id":"minecraft:lilac","localizedName":"Lilac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lilac"},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_of_the_valley"},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_pad"},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.lime_banner"},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_bed"},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_candle"},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_carpet"},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete"},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete_powder"},{"id":"minecraft:lime_dye","localizedName":"Lime Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lime_dye"},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_glazed_terracotta"},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_shulker_box"},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass"},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass_pane"},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_terracotta"},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_wool"},{"id":"minecraft:lingering_potion","localizedName":"Lingering Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lingering_potion.effect.water"},{"id":"minecraft:llama_spawn_egg","localizedName":"Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.llama_spawn_egg"},{"id":"minecraft:lodestone","localizedName":"Lodestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lodestone"},{"id":"minecraft:loom","localizedName":"Loom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.loom"},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.magenta_banner"},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_bed"},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_candle"},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_carpet"},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete"},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete_powder"},{"id":"minecraft:magenta_dye","localizedName":"Magenta Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magenta_dye"},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_glazed_terracotta"},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_shulker_box"},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass"},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass_pane"},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_terracotta"},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_wool"},{"id":"minecraft:magma_block","localizedName":"Magma Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magma_block"},{"id":"minecraft:magma_cream","localizedName":"Magma Cream","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cream"},{"id":"minecraft:magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cube_spawn_egg"},{"id":"minecraft:mangrove_boat","localizedName":"Mangrove Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mangrove_boat"},{"id":"minecraft:mangrove_button","localizedName":"Mangrove Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_button"},{"id":"minecraft:mangrove_chest_boat","localizedName":"Mangrove Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mangrove_chest_boat"},{"id":"minecraft:mangrove_door","localizedName":"Mangrove Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_door"},{"id":"minecraft:mangrove_fence","localizedName":"Mangrove Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_fence"},{"id":"minecraft:mangrove_fence_gate","localizedName":"Mangrove Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_fence_gate"},{"id":"minecraft:mangrove_leaves","localizedName":"Mangrove Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_leaves"},{"id":"minecraft:mangrove_log","localizedName":"Mangrove Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_log"},{"id":"minecraft:mangrove_planks","localizedName":"Mangrove Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_planks"},{"id":"minecraft:mangrove_pressure_plate","localizedName":"Mangrove Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_pressure_plate"},{"id":"minecraft:mangrove_propagule","localizedName":"Mangrove Propagule","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_propagule"},{"id":"minecraft:mangrove_roots","localizedName":"Mangrove Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_roots"},{"id":"minecraft:mangrove_sign","localizedName":"Mangrove Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.mangrove_sign"},{"id":"minecraft:mangrove_slab","localizedName":"Mangrove Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_slab"},{"id":"minecraft:mangrove_stairs","localizedName":"Mangrove Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_stairs"},{"id":"minecraft:mangrove_trapdoor","localizedName":"Mangrove Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_trapdoor"},{"id":"minecraft:mangrove_wood","localizedName":"Mangrove Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_wood"},{"id":"minecraft:map","localizedName":"Empty Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.map"},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.medium_amethyst_bud"},{"id":"minecraft:melon","localizedName":"Melon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.melon"},{"id":"minecraft:melon_seeds","localizedName":"Melon Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_seeds"},{"id":"minecraft:melon_slice","localizedName":"Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_slice"},{"id":"minecraft:milk_bucket","localizedName":"Milk Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.milk_bucket"},{"id":"minecraft:minecart","localizedName":"Minecart","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.minecart"},{"id":"minecraft:mojang_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mojang_banner_pattern"},{"id":"minecraft:mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mooshroom_spawn_egg"},{"id":"minecraft:moss_block","localizedName":"Moss Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.moss_block"},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.moss_carpet"},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone"},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_slab"},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_stairs"},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_wall"},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_slab"},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_stairs"},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_wall"},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_bricks"},{"id":"minecraft:mud","localizedName":"Mud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud"},{"id":"minecraft:mud_brick_slab","localizedName":"Mud Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_slab"},{"id":"minecraft:mud_brick_stairs","localizedName":"Mud Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_stairs"},{"id":"minecraft:mud_brick_wall","localizedName":"Mud Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_wall"},{"id":"minecraft:mud_bricks","localizedName":"Mud Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_bricks"},{"id":"minecraft:muddy_mangrove_roots","localizedName":"Muddy Mangrove Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.muddy_mangrove_roots"},{"id":"minecraft:mule_spawn_egg","localizedName":"Mule Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mule_spawn_egg"},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mushroom_stem"},{"id":"minecraft:mushroom_stew","localizedName":"Mushroom Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mushroom_stew"},{"id":"minecraft:music_disc_11","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_11"},{"id":"minecraft:music_disc_13","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_13"},{"id":"minecraft:music_disc_5","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_5"},{"id":"minecraft:music_disc_blocks","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_blocks"},{"id":"minecraft:music_disc_cat","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_cat"},{"id":"minecraft:music_disc_chirp","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_chirp"},{"id":"minecraft:music_disc_far","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_far"},{"id":"minecraft:music_disc_mall","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mall"},{"id":"minecraft:music_disc_mellohi","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mellohi"},{"id":"minecraft:music_disc_otherside","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_otherside"},{"id":"minecraft:music_disc_pigstep","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_pigstep"},{"id":"minecraft:music_disc_stal","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_stal"},{"id":"minecraft:music_disc_strad","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_strad"},{"id":"minecraft:music_disc_wait","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_wait"},{"id":"minecraft:music_disc_ward","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_ward"},{"id":"minecraft:mutton","localizedName":"Raw Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mutton"},{"id":"minecraft:mycelium","localizedName":"Mycelium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mycelium"},{"id":"minecraft:name_tag","localizedName":"Name Tag","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.name_tag"},{"id":"minecraft:nautilus_shell","localizedName":"Nautilus Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nautilus_shell"},{"id":"minecraft:nether_brick","localizedName":"Nether Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_brick"},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_fence"},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_slab"},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_stairs"},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_wall"},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_bricks"},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_gold_ore"},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_quartz_ore"},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_sprouts"},{"id":"minecraft:nether_star","localizedName":"Nether Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_star"},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_wart"},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_wart_block"},{"id":"minecraft:netherite_axe","localizedName":"Netherite Axe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_axe"},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherite_block"},{"id":"minecraft:netherite_boots","localizedName":"Netherite Boots","maxDamage":481,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_boots"},{"id":"minecraft:netherite_chestplate","localizedName":"Netherite Chestplate","maxDamage":592,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_chestplate"},{"id":"minecraft:netherite_helmet","localizedName":"Netherite Helmet","maxDamage":407,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_helmet"},{"id":"minecraft:netherite_hoe","localizedName":"Netherite Hoe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_hoe"},{"id":"minecraft:netherite_ingot","localizedName":"Netherite Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_ingot"},{"id":"minecraft:netherite_leggings","localizedName":"Netherite Leggings","maxDamage":555,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_leggings"},{"id":"minecraft:netherite_pickaxe","localizedName":"Netherite Pickaxe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_pickaxe"},{"id":"minecraft:netherite_scrap","localizedName":"Netherite Scrap","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_scrap"},{"id":"minecraft:netherite_shovel","localizedName":"Netherite Shovel","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_shovel"},{"id":"minecraft:netherite_sword","localizedName":"Netherite Sword","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_sword"},{"id":"minecraft:netherrack","localizedName":"Netherrack","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherrack"},{"id":"minecraft:note_block","localizedName":"Note Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.note_block"},{"id":"minecraft:oak_boat","localizedName":"Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.oak_boat"},{"id":"minecraft:oak_button","localizedName":"Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_button"},{"id":"minecraft:oak_chest_boat","localizedName":"Oak Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.oak_chest_boat"},{"id":"minecraft:oak_door","localizedName":"Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_door"},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence"},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence_gate"},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_leaves"},{"id":"minecraft:oak_log","localizedName":"Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_log"},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_planks"},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_pressure_plate"},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_sapling"},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.oak_sign"},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_slab"},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_stairs"},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_trapdoor"},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_wood"},{"id":"minecraft:observer","localizedName":"Observer","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.observer"},{"id":"minecraft:obsidian","localizedName":"Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.obsidian"},{"id":"minecraft:ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ocelot_spawn_egg"},{"id":"minecraft:ochre_froglight","localizedName":"Ochre Froglight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ochre_froglight"},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.orange_banner"},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_bed"},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_candle"},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_carpet"},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete"},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete_powder"},{"id":"minecraft:orange_dye","localizedName":"Orange Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.orange_dye"},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_glazed_terracotta"},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_shulker_box"},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass"},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass_pane"},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_terracotta"},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_tulip"},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_wool"},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxeye_daisy"},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper"},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper"},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_slab"},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_stairs"},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.packed_ice"},{"id":"minecraft:packed_mud","localizedName":"Packed Mud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.packed_mud"},{"id":"minecraft:painting","localizedName":"Painting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.painting"},{"id":"minecraft:panda_spawn_egg","localizedName":"Panda Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.panda_spawn_egg"},{"id":"minecraft:paper","localizedName":"Paper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.paper"},{"id":"minecraft:parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.parrot_spawn_egg"},{"id":"minecraft:pearlescent_froglight","localizedName":"Pearlescent Froglight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pearlescent_froglight"},{"id":"minecraft:peony","localizedName":"Peony","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.peony"},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.petrified_oak_slab"},{"id":"minecraft:phantom_membrane","localizedName":"Phantom Membrane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_membrane"},{"id":"minecraft:phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_spawn_egg"},{"id":"minecraft:pig_spawn_egg","localizedName":"Pig Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pig_spawn_egg"},{"id":"minecraft:piglin_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.piglin_banner_pattern"},{"id":"minecraft:piglin_brute_spawn_egg","localizedName":"Piglin Brute Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_brute_spawn_egg"},{"id":"minecraft:piglin_spawn_egg","localizedName":"Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_spawn_egg"},{"id":"minecraft:pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pillager_spawn_egg"},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.pink_banner"},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_bed"},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_candle"},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_carpet"},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete"},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete_powder"},{"id":"minecraft:pink_dye","localizedName":"Pink Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pink_dye"},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_glazed_terracotta"},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_shulker_box"},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass"},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass_pane"},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_terracotta"},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_tulip"},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_wool"},{"id":"minecraft:piston","localizedName":"Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.piston"},{"id":"minecraft:player_head","localizedName":"Player Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.player_head"},{"id":"minecraft:podzol","localizedName":"Podzol","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.podzol"},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pointed_dripstone"},{"id":"minecraft:poisonous_potato","localizedName":"Poisonous Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.poisonous_potato"},{"id":"minecraft:polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.polar_bear_spawn_egg"},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite"},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_slab"},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_stairs"},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_basalt"},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone"},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_slab"},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_stairs"},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_wall"},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_bricks"},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_button"},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_pressure_plate"},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_slab"},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_stairs"},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_wall"},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate"},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_slab"},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_stairs"},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_wall"},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite"},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_slab"},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_stairs"},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite"},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_slab"},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_stairs"},{"id":"minecraft:popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.popped_chorus_fruit"},{"id":"minecraft:poppy","localizedName":"Poppy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.poppy"},{"id":"minecraft:porkchop","localizedName":"Raw Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.porkchop"},{"id":"minecraft:potato","localizedName":"Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.potato"},{"id":"minecraft:potion","localizedName":"Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.potion.effect.water"},{"id":"minecraft:powder_snow_bucket","localizedName":"Powder Snow Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.powder_snow_bucket"},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.powered_rail"},{"id":"minecraft:prismarine","localizedName":"Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine"},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_slab"},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_stairs"},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_bricks"},{"id":"minecraft:prismarine_crystals","localizedName":"Prismarine Crystals","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_crystals"},{"id":"minecraft:prismarine_shard","localizedName":"Prismarine Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_shard"},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_slab"},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_stairs"},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_wall"},{"id":"minecraft:pufferfish","localizedName":"Pufferfish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish"},{"id":"minecraft:pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.pufferfish_bucket"},{"id":"minecraft:pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish_spawn_egg"},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pumpkin"},{"id":"minecraft:pumpkin_pie","localizedName":"Pumpkin Pie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_pie"},{"id":"minecraft:pumpkin_seeds","localizedName":"Pumpkin Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_seeds"},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.purple_banner"},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_bed"},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_candle"},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_carpet"},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete"},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete_powder"},{"id":"minecraft:purple_dye","localizedName":"Purple Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.purple_dye"},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_glazed_terracotta"},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_shulker_box"},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass"},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass_pane"},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_terracotta"},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_wool"},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_block"},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_pillar"},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_slab"},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_stairs"},{"id":"minecraft:quartz","localizedName":"Nether Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.quartz"},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_block"},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_bricks"},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_pillar"},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_slab"},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_stairs"},{"id":"minecraft:rabbit","localizedName":"Raw Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit"},{"id":"minecraft:rabbit_foot","localizedName":"Rabbit\u0027s Foot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_foot"},{"id":"minecraft:rabbit_hide","localizedName":"Rabbit Hide","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_hide"},{"id":"minecraft:rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_spawn_egg"},{"id":"minecraft:rabbit_stew","localizedName":"Rabbit Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.rabbit_stew"},{"id":"minecraft:rail","localizedName":"Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rail"},{"id":"minecraft:ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ravager_spawn_egg"},{"id":"minecraft:raw_copper","localizedName":"Raw Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_copper"},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_copper_block"},{"id":"minecraft:raw_gold","localizedName":"Raw Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_gold"},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_gold_block"},{"id":"minecraft:raw_iron","localizedName":"Raw Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_iron"},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_iron_block"},{"id":"minecraft:recovery_compass","localizedName":"Recovery Compass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.recovery_compass"},{"id":"minecraft:red_banner","localizedName":"Red Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.red_banner"},{"id":"minecraft:red_bed","localizedName":"Red Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_bed"},{"id":"minecraft:red_candle","localizedName":"Red Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_candle"},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_carpet"},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete"},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete_powder"},{"id":"minecraft:red_dye","localizedName":"Red Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.red_dye"},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_glazed_terracotta"},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom"},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom_block"},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_slab"},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_stairs"},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_wall"},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_bricks"},{"id":"minecraft:red_sand","localizedName":"Red Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sand"},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone"},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_slab"},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_stairs"},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_wall"},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_shulker_box"},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass"},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass_pane"},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_terracotta"},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_tulip"},{"id":"minecraft:red_wool","localizedName":"Red Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_wool"},{"id":"minecraft:redstone","localizedName":"Redstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.redstone"},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_block"},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_lamp"},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_ore"},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_torch"},{"id":"minecraft:reinforced_deepslate","localizedName":"Reinforced Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.reinforced_deepslate"},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeater"},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeating_command_block"},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.respawn_anchor"},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rooted_dirt"},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rose_bush"},{"id":"minecraft:rotten_flesh","localizedName":"Rotten Flesh","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rotten_flesh"},{"id":"minecraft:saddle","localizedName":"Saddle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.saddle"},{"id":"minecraft:salmon","localizedName":"Raw Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon"},{"id":"minecraft:salmon_bucket","localizedName":"Bucket of Salmon","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.salmon_bucket"},{"id":"minecraft:salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon_spawn_egg"},{"id":"minecraft:sand","localizedName":"Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sand"},{"id":"minecraft:sandstone","localizedName":"Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone"},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_slab"},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_stairs"},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_wall"},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.scaffolding"},{"id":"minecraft:sculk","localizedName":"Sculk","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk"},{"id":"minecraft:sculk_catalyst","localizedName":"Sculk Catalyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_catalyst"},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_sensor"},{"id":"minecraft:sculk_shrieker","localizedName":"Sculk Shrieker","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_shrieker"},{"id":"minecraft:sculk_vein","localizedName":"Sculk Vein","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_vein"},{"id":"minecraft:scute","localizedName":"Scute","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.scute"},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_lantern"},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_pickle"},{"id":"minecraft:seagrass","localizedName":"Seagrass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.seagrass"},{"id":"minecraft:shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1,"unlocalizedName":"item.minecraft.shears"},{"id":"minecraft:sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sheep_spawn_egg"},{"id":"minecraft:shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1,"unlocalizedName":"item.minecraft.shield"},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.shroomlight"},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.shulker_box"},{"id":"minecraft:shulker_shell","localizedName":"Shulker Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_shell"},{"id":"minecraft:shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_spawn_egg"},{"id":"minecraft:silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.silverfish_spawn_egg"},{"id":"minecraft:skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg"},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.skeleton_skull"},{"id":"minecraft:skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_spawn_egg"},{"id":"minecraft:skull_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.skull_banner_pattern"},{"id":"minecraft:slime_ball","localizedName":"Slimeball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_ball"},{"id":"minecraft:slime_block","localizedName":"Slime Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.slime_block"},{"id":"minecraft:slime_spawn_egg","localizedName":"Slime Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_spawn_egg"},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.small_amethyst_bud"},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.small_dripleaf"},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smithing_table"},{"id":"minecraft:smoker","localizedName":"Smoker","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smoker"},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_basalt"},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz"},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_slab"},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_stairs"},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone"},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_slab"},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs"},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone"},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_slab"},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_stairs"},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone"},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone_slab"},{"id":"minecraft:snow","localizedName":"Snow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow"},{"id":"minecraft:snow_block","localizedName":"Snow Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow_block"},{"id":"minecraft:snowball","localizedName":"Snowball","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.snowball"},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_campfire"},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_lantern"},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_sand"},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_soil"},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_torch"},{"id":"minecraft:spawner","localizedName":"Spawner","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spawner"},{"id":"minecraft:spectral_arrow","localizedName":"Spectral Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spectral_arrow"},{"id":"minecraft:spider_eye","localizedName":"Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_eye"},{"id":"minecraft:spider_spawn_egg","localizedName":"Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_spawn_egg"},{"id":"minecraft:splash_potion","localizedName":"Splash Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.splash_potion.effect.water"},{"id":"minecraft:sponge","localizedName":"Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sponge"},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spore_blossom"},{"id":"minecraft:spruce_boat","localizedName":"Spruce Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_boat"},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_button"},{"id":"minecraft:spruce_chest_boat","localizedName":"Spruce Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_chest_boat"},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_door"},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence"},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence_gate"},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_leaves"},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_log"},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_planks"},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_pressure_plate"},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_sapling"},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_sign"},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_slab"},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_stairs"},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_trapdoor"},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_wood"},{"id":"minecraft:spyglass","localizedName":"Spyglass","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spyglass"},{"id":"minecraft:squid_spawn_egg","localizedName":"Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.squid_spawn_egg"},{"id":"minecraft:stick","localizedName":"Stick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stick"},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sticky_piston"},{"id":"minecraft:stone","localizedName":"Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone"},{"id":"minecraft:stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_axe"},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_slab"},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_stairs"},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_wall"},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_bricks"},{"id":"minecraft:stone_button","localizedName":"Stone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_button"},{"id":"minecraft:stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_hoe"},{"id":"minecraft:stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_pickaxe"},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_pressure_plate"},{"id":"minecraft:stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_shovel"},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_slab"},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_stairs"},{"id":"minecraft:stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_sword"},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stonecutter"},{"id":"minecraft:stray_spawn_egg","localizedName":"Stray Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stray_spawn_egg"},{"id":"minecraft:strider_spawn_egg","localizedName":"Strider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.strider_spawn_egg"},{"id":"minecraft:string","localizedName":"String","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.string"},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_log"},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_wood"},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_log"},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_wood"},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_hyphae"},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_stem"},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_log"},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_wood"},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_log"},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_wood"},{"id":"minecraft:stripped_mangrove_log","localizedName":"Stripped Mangrove Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_mangrove_log"},{"id":"minecraft:stripped_mangrove_wood","localizedName":"Stripped Mangrove Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_mangrove_wood"},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_log"},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_wood"},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_log"},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_wood"},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_hyphae"},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_stem"},{"id":"minecraft:structure_block","localizedName":"Structure Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_block"},{"id":"minecraft:structure_void","localizedName":"Structure Void","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_void"},{"id":"minecraft:sugar","localizedName":"Sugar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sugar"},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sugar_cane"},{"id":"minecraft:sunflower","localizedName":"Sunflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sunflower"},{"id":"minecraft:suspicious_stew","localizedName":"Suspicious Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.suspicious_stew"},{"id":"minecraft:sweet_berries","localizedName":"Sweet Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sweet_berries"},{"id":"minecraft:tadpole_bucket","localizedName":"Bucket of Tadpole","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tadpole_bucket"},{"id":"minecraft:tadpole_spawn_egg","localizedName":"Tadpole Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tadpole_spawn_egg"},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tall_grass"},{"id":"minecraft:target","localizedName":"Target","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.target"},{"id":"minecraft:terracotta","localizedName":"Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.terracotta"},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tinted_glass"},{"id":"minecraft:tipped_arrow","localizedName":"Arrow of Poison","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tipped_arrow.effect.poison"},{"id":"minecraft:tnt","localizedName":"TNT","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tnt"},{"id":"minecraft:tnt_minecart","localizedName":"Minecart with TNT","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tnt_minecart"},{"id":"minecraft:torch","localizedName":"Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.torch"},{"id":"minecraft:totem_of_undying","localizedName":"Totem of Undying","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.totem_of_undying"},{"id":"minecraft:trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.trader_llama_spawn_egg"},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.trapped_chest"},{"id":"minecraft:trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.trident"},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tripwire_hook"},{"id":"minecraft:tropical_fish","localizedName":"Tropical Fish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish"},{"id":"minecraft:tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tropical_fish_bucket"},{"id":"minecraft:tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish_spawn_egg"},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral"},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_block"},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_fan"},{"id":"minecraft:tuff","localizedName":"Tuff","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tuff"},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.turtle_egg"},{"id":"minecraft:turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1,"unlocalizedName":"item.minecraft.turtle_helmet"},{"id":"minecraft:turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_spawn_egg"},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.twisting_vines"},{"id":"minecraft:verdant_froglight","localizedName":"Verdant Froglight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.verdant_froglight"},{"id":"minecraft:vex_spawn_egg","localizedName":"Vex Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vex_spawn_egg"},{"id":"minecraft:villager_spawn_egg","localizedName":"Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.villager_spawn_egg"},{"id":"minecraft:vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vindicator_spawn_egg"},{"id":"minecraft:vine","localizedName":"Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.vine"},{"id":"minecraft:wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wandering_trader_spawn_egg"},{"id":"minecraft:warden_spawn_egg","localizedName":"Warden Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.warden_spawn_egg"},{"id":"minecraft:warped_button","localizedName":"Warped Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_button"},{"id":"minecraft:warped_door","localizedName":"Warped Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_door"},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence"},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence_gate"},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fungus"},{"id":"minecraft:warped_fungus_on_a_stick","localizedName":"Warped Fungus on a Stick","maxDamage":100,"maxStackSize":1,"unlocalizedName":"item.minecraft.warped_fungus_on_a_stick"},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_hyphae"},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_nylium"},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_planks"},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_pressure_plate"},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_roots"},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.warped_sign"},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_slab"},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stairs"},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stem"},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_trapdoor"},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_wart_block"},{"id":"minecraft:water_bucket","localizedName":"Water Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.water_bucket"},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_block"},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper"},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_slab"},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_stairs"},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper"},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper"},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_slab"},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_stairs"},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper"},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper"},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_slab"},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_stairs"},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper"},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper"},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_slab"},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_stairs"},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper"},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper"},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_slab"},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_stairs"},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weeping_vines"},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wet_sponge"},{"id":"minecraft:wheat","localizedName":"Wheat","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat"},{"id":"minecraft:wheat_seeds","localizedName":"Wheat Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat_seeds"},{"id":"minecraft:white_banner","localizedName":"White Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.white_banner"},{"id":"minecraft:white_bed","localizedName":"White Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_bed"},{"id":"minecraft:white_candle","localizedName":"White Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_candle"},{"id":"minecraft:white_carpet","localizedName":"White Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_carpet"},{"id":"minecraft:white_concrete","localizedName":"White Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete"},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete_powder"},{"id":"minecraft:white_dye","localizedName":"White Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.white_dye"},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_glazed_terracotta"},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_shulker_box"},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass"},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass_pane"},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_terracotta"},{"id":"minecraft:white_tulip","localizedName":"White Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_tulip"},{"id":"minecraft:white_wool","localizedName":"White Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_wool"},{"id":"minecraft:witch_spawn_egg","localizedName":"Witch Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.witch_spawn_egg"},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_rose"},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_skeleton_skull"},{"id":"minecraft:wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg"},{"id":"minecraft:wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wolf_spawn_egg"},{"id":"minecraft:wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_axe"},{"id":"minecraft:wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_hoe"},{"id":"minecraft:wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_pickaxe"},{"id":"minecraft:wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_shovel"},{"id":"minecraft:wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_sword"},{"id":"minecraft:writable_book","localizedName":"Book and Quill","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.writable_book"},{"id":"minecraft:written_book","localizedName":"Written Book","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.written_book"},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.yellow_banner"},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_bed"},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_candle"},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_carpet"},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete"},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete_powder"},{"id":"minecraft:yellow_dye","localizedName":"Yellow Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.yellow_dye"},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_glazed_terracotta"},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_shulker_box"},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass"},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass_pane"},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_terracotta"},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_wool"},{"id":"minecraft:zoglin_spawn_egg","localizedName":"Zoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zoglin_spawn_egg"},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.zombie_head"},{"id":"minecraft:zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_horse_spawn_egg"},{"id":"minecraft:zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_spawn_egg"},{"id":"minecraft:zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_villager_spawn_egg"},{"id":"minecraft:zombified_piglin_spawn_egg","localizedName":"Zombified Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombified_piglin_spawn_egg"}] diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/items.120.json b/src/main/resources/com/sk89q/worldedit/world/registry/items.120.json new file mode 100644 index 0000000..47b2326 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/items.120.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_boat","localizedName":"Acacia Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_boat"},{"id":"minecraft:acacia_button","localizedName":"Acacia Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_button"},{"id":"minecraft:acacia_chest_boat","localizedName":"Acacia Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_chest_boat"},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_door"},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence"},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence_gate"},{"id":"minecraft:acacia_hanging_sign","localizedName":"Acacia Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_hanging_sign"},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_leaves"},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_log"},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_planks"},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_pressure_plate"},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_sapling"},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_sign"},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_slab"},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_stairs"},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_trapdoor"},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_wood"},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.activator_rail"},{"id":"minecraft:air","localizedName":"Air","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.air"},{"id":"minecraft:allay_spawn_egg","localizedName":"Allay Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.allay_spawn_egg"},{"id":"minecraft:allium","localizedName":"Allium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.allium"},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_block"},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_cluster"},{"id":"minecraft:amethyst_shard","localizedName":"Amethyst Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.amethyst_shard"},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ancient_debris"},{"id":"minecraft:andesite","localizedName":"Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite"},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_slab"},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_stairs"},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_wall"},{"id":"minecraft:angler_pottery_sherd","localizedName":"Angler Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.angler_pottery_sherd"},{"id":"minecraft:anvil","localizedName":"Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.anvil"},{"id":"minecraft:apple","localizedName":"Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.apple"},{"id":"minecraft:archer_pottery_sherd","localizedName":"Archer Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.archer_pottery_sherd"},{"id":"minecraft:armor_stand","localizedName":"Armor Stand","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.armor_stand"},{"id":"minecraft:arms_up_pottery_sherd","localizedName":"Arms Up Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.arms_up_pottery_sherd"},{"id":"minecraft:arrow","localizedName":"Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.arrow"},{"id":"minecraft:axolotl_bucket","localizedName":"Bucket of Axolotl","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.axolotl_bucket"},{"id":"minecraft:axolotl_spawn_egg","localizedName":"Axolotl Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.axolotl_spawn_egg"},{"id":"minecraft:azalea","localizedName":"Azalea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azalea"},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azalea_leaves"},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azure_bluet"},{"id":"minecraft:baked_potato","localizedName":"Baked Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.baked_potato"},{"id":"minecraft:bamboo","localizedName":"Bamboo","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo"},{"id":"minecraft:bamboo_block","localizedName":"Block of Bamboo","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_block"},{"id":"minecraft:bamboo_button","localizedName":"Bamboo Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_button"},{"id":"minecraft:bamboo_chest_raft","localizedName":"Bamboo Raft with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.bamboo_chest_raft"},{"id":"minecraft:bamboo_door","localizedName":"Bamboo Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_door"},{"id":"minecraft:bamboo_fence","localizedName":"Bamboo Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_fence"},{"id":"minecraft:bamboo_fence_gate","localizedName":"Bamboo Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_fence_gate"},{"id":"minecraft:bamboo_hanging_sign","localizedName":"Bamboo Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.bamboo_hanging_sign"},{"id":"minecraft:bamboo_mosaic","localizedName":"Bamboo Mosaic","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_mosaic"},{"id":"minecraft:bamboo_mosaic_slab","localizedName":"Bamboo Mosaic Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_mosaic_slab"},{"id":"minecraft:bamboo_mosaic_stairs","localizedName":"Bamboo Mosaic Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_mosaic_stairs"},{"id":"minecraft:bamboo_planks","localizedName":"Bamboo Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_planks"},{"id":"minecraft:bamboo_pressure_plate","localizedName":"Bamboo Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_pressure_plate"},{"id":"minecraft:bamboo_raft","localizedName":"Bamboo Raft","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.bamboo_raft"},{"id":"minecraft:bamboo_sign","localizedName":"Bamboo Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.bamboo_sign"},{"id":"minecraft:bamboo_slab","localizedName":"Bamboo Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_slab"},{"id":"minecraft:bamboo_stairs","localizedName":"Bamboo Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_stairs"},{"id":"minecraft:bamboo_trapdoor","localizedName":"Bamboo Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_trapdoor"},{"id":"minecraft:barrel","localizedName":"Barrel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrel"},{"id":"minecraft:barrier","localizedName":"Barrier","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrier"},{"id":"minecraft:basalt","localizedName":"Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.basalt"},{"id":"minecraft:bat_spawn_egg","localizedName":"Bat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bat_spawn_egg"},{"id":"minecraft:beacon","localizedName":"Beacon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beacon"},{"id":"minecraft:bedrock","localizedName":"Bedrock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bedrock"},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bee_nest"},{"id":"minecraft:bee_spawn_egg","localizedName":"Bee Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bee_spawn_egg"},{"id":"minecraft:beef","localizedName":"Raw Beef","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beef"},{"id":"minecraft:beehive","localizedName":"Beehive","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beehive"},{"id":"minecraft:beetroot","localizedName":"Beetroot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot"},{"id":"minecraft:beetroot_seeds","localizedName":"Beetroot Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot_seeds"},{"id":"minecraft:beetroot_soup","localizedName":"Beetroot Soup","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.beetroot_soup"},{"id":"minecraft:bell","localizedName":"Bell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bell"},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.big_dripleaf"},{"id":"minecraft:birch_boat","localizedName":"Birch Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.birch_boat"},{"id":"minecraft:birch_button","localizedName":"Birch Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_button"},{"id":"minecraft:birch_chest_boat","localizedName":"Birch Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.birch_chest_boat"},{"id":"minecraft:birch_door","localizedName":"Birch Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_door"},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence"},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence_gate"},{"id":"minecraft:birch_hanging_sign","localizedName":"Birch Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.birch_hanging_sign"},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_leaves"},{"id":"minecraft:birch_log","localizedName":"Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_log"},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_planks"},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_pressure_plate"},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_sapling"},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.birch_sign"},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_slab"},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_stairs"},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_trapdoor"},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_wood"},{"id":"minecraft:black_banner","localizedName":"Black Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.black_banner"},{"id":"minecraft:black_bed","localizedName":"Black Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_bed"},{"id":"minecraft:black_candle","localizedName":"Black Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_candle"},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_carpet"},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete"},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete_powder"},{"id":"minecraft:black_dye","localizedName":"Black Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.black_dye"},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_glazed_terracotta"},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_shulker_box"},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass"},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass_pane"},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_terracotta"},{"id":"minecraft:black_wool","localizedName":"Black Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_wool"},{"id":"minecraft:blackstone","localizedName":"Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone"},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_slab"},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_stairs"},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_wall"},{"id":"minecraft:blade_pottery_sherd","localizedName":"Blade Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blade_pottery_sherd"},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blast_furnace"},{"id":"minecraft:blaze_powder","localizedName":"Blaze Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_powder"},{"id":"minecraft:blaze_rod","localizedName":"Blaze Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_rod"},{"id":"minecraft:blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_spawn_egg"},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.blue_banner"},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_bed"},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_candle"},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_carpet"},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete"},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete_powder"},{"id":"minecraft:blue_dye","localizedName":"Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blue_dye"},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_glazed_terracotta"},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_ice"},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_orchid"},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_shulker_box"},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass"},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass_pane"},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_terracotta"},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_wool"},{"id":"minecraft:bone","localizedName":"Bone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone"},{"id":"minecraft:bone_block","localizedName":"Bone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bone_block"},{"id":"minecraft:bone_meal","localizedName":"Bone Meal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone_meal"},{"id":"minecraft:book","localizedName":"Book","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.book"},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bookshelf"},{"id":"minecraft:bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1,"unlocalizedName":"item.minecraft.bow"},{"id":"minecraft:bowl","localizedName":"Bowl","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bowl"},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral"},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_block"},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_fan"},{"id":"minecraft:bread","localizedName":"Bread","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bread"},{"id":"minecraft:brewer_pottery_sherd","localizedName":"Brewer Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brewer_pottery_sherd"},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brewing_stand"},{"id":"minecraft:brick","localizedName":"Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brick"},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_slab"},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_stairs"},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_wall"},{"id":"minecraft:bricks","localizedName":"Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bricks"},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.brown_banner"},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_bed"},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_candle"},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_carpet"},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete"},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete_powder"},{"id":"minecraft:brown_dye","localizedName":"Brown Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brown_dye"},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_glazed_terracotta"},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom"},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom_block"},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_shulker_box"},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass"},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass_pane"},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_terracotta"},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_wool"},{"id":"minecraft:brush","localizedName":"Brush","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.brush"},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral"},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_block"},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_fan"},{"id":"minecraft:bucket","localizedName":"Bucket","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.bucket"},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.budding_amethyst"},{"id":"minecraft:bundle","localizedName":"Bundle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.bundle"},{"id":"minecraft:burn_pottery_sherd","localizedName":"Burn Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.burn_pottery_sherd"},{"id":"minecraft:cactus","localizedName":"Cactus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cactus"},{"id":"minecraft:cake","localizedName":"Cake","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cake"},{"id":"minecraft:calcite","localizedName":"Calcite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.calcite"},{"id":"minecraft:calibrated_sculk_sensor","localizedName":"Calibrated Sculk Sensor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.calibrated_sculk_sensor"},{"id":"minecraft:camel_spawn_egg","localizedName":"Camel Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.camel_spawn_egg"},{"id":"minecraft:campfire","localizedName":"Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.campfire"},{"id":"minecraft:candle","localizedName":"Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.candle"},{"id":"minecraft:carrot","localizedName":"Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.carrot"},{"id":"minecraft:carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1,"unlocalizedName":"item.minecraft.carrot_on_a_stick"},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cartography_table"},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.carved_pumpkin"},{"id":"minecraft:cat_spawn_egg","localizedName":"Cat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cat_spawn_egg"},{"id":"minecraft:cauldron","localizedName":"Cauldron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cauldron"},{"id":"minecraft:cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cave_spider_spawn_egg"},{"id":"minecraft:chain","localizedName":"Chain","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain"},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain_command_block"},{"id":"minecraft:chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_boots"},{"id":"minecraft:chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_chestplate"},{"id":"minecraft:chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_helmet"},{"id":"minecraft:chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_leggings"},{"id":"minecraft:charcoal","localizedName":"Charcoal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.charcoal"},{"id":"minecraft:cherry_boat","localizedName":"Cherry Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.cherry_boat"},{"id":"minecraft:cherry_button","localizedName":"Cherry Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_button"},{"id":"minecraft:cherry_chest_boat","localizedName":"Cherry Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.cherry_chest_boat"},{"id":"minecraft:cherry_door","localizedName":"Cherry Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_door"},{"id":"minecraft:cherry_fence","localizedName":"Cherry Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_fence"},{"id":"minecraft:cherry_fence_gate","localizedName":"Cherry Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_fence_gate"},{"id":"minecraft:cherry_hanging_sign","localizedName":"Cherry Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.cherry_hanging_sign"},{"id":"minecraft:cherry_leaves","localizedName":"Cherry Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_leaves"},{"id":"minecraft:cherry_log","localizedName":"Cherry Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_log"},{"id":"minecraft:cherry_planks","localizedName":"Cherry Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_planks"},{"id":"minecraft:cherry_pressure_plate","localizedName":"Cherry Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_pressure_plate"},{"id":"minecraft:cherry_sapling","localizedName":"Cherry Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_sapling"},{"id":"minecraft:cherry_sign","localizedName":"Cherry Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.cherry_sign"},{"id":"minecraft:cherry_slab","localizedName":"Cherry Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_slab"},{"id":"minecraft:cherry_stairs","localizedName":"Cherry Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_stairs"},{"id":"minecraft:cherry_trapdoor","localizedName":"Cherry Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_trapdoor"},{"id":"minecraft:cherry_wood","localizedName":"Cherry Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_wood"},{"id":"minecraft:chest","localizedName":"Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chest"},{"id":"minecraft:chest_minecart","localizedName":"Minecart with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.chest_minecart"},{"id":"minecraft:chicken","localizedName":"Raw Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken"},{"id":"minecraft:chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken_spawn_egg"},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chipped_anvil"},{"id":"minecraft:chiseled_bookshelf","localizedName":"Chiseled Bookshelf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_bookshelf"},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_deepslate"},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_nether_bricks"},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_polished_blackstone"},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_quartz_block"},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_red_sandstone"},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_sandstone"},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_stone_bricks"},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_flower"},{"id":"minecraft:chorus_fruit","localizedName":"Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chorus_fruit"},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_plant"},{"id":"minecraft:clay","localizedName":"Clay","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.clay"},{"id":"minecraft:clay_ball","localizedName":"Clay Ball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clay_ball"},{"id":"minecraft:clock","localizedName":"Clock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clock"},{"id":"minecraft:coal","localizedName":"Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.coal"},{"id":"minecraft:coal_block","localizedName":"Block of Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_block"},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_ore"},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coarse_dirt"},{"id":"minecraft:coast_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate"},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_slab"},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_stairs"},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_wall"},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone"},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_slab"},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_stairs"},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_wall"},{"id":"minecraft:cobweb","localizedName":"Cobweb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobweb"},{"id":"minecraft:cocoa_beans","localizedName":"Cocoa Beans","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cocoa_beans"},{"id":"minecraft:cod","localizedName":"Raw Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod"},{"id":"minecraft:cod_bucket","localizedName":"Bucket of Cod","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.cod_bucket"},{"id":"minecraft:cod_spawn_egg","localizedName":"Cod Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod_spawn_egg"},{"id":"minecraft:command_block","localizedName":"Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.command_block"},{"id":"minecraft:command_block_minecart","localizedName":"Minecart with Command Block","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.command_block_minecart"},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.comparator"},{"id":"minecraft:compass","localizedName":"Compass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.compass"},{"id":"minecraft:composter","localizedName":"Composter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.composter"},{"id":"minecraft:conduit","localizedName":"Conduit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.conduit"},{"id":"minecraft:cooked_beef","localizedName":"Steak","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_beef"},{"id":"minecraft:cooked_chicken","localizedName":"Cooked Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_chicken"},{"id":"minecraft:cooked_cod","localizedName":"Cooked Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_cod"},{"id":"minecraft:cooked_mutton","localizedName":"Cooked Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_mutton"},{"id":"minecraft:cooked_porkchop","localizedName":"Cooked Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_porkchop"},{"id":"minecraft:cooked_rabbit","localizedName":"Cooked Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_rabbit"},{"id":"minecraft:cooked_salmon","localizedName":"Cooked Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_salmon"},{"id":"minecraft:cookie","localizedName":"Cookie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cookie"},{"id":"minecraft:copper_block","localizedName":"Block of Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.copper_block"},{"id":"minecraft:copper_ingot","localizedName":"Copper Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.copper_ingot"},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.copper_ore"},{"id":"minecraft:cornflower","localizedName":"Cornflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cornflower"},{"id":"minecraft:cow_spawn_egg","localizedName":"Cow Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cow_spawn_egg"},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_bricks"},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_tiles"},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_nether_bricks"},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_polished_blackstone_bricks"},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_stone_bricks"},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crafting_table"},{"id":"minecraft:creeper_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.creeper_banner_pattern"},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.creeper_head"},{"id":"minecraft:creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.creeper_spawn_egg"},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_button"},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_door"},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence"},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence_gate"},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fungus"},{"id":"minecraft:crimson_hanging_sign","localizedName":"Crimson Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_hanging_sign"},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_hyphae"},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_nylium"},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_planks"},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_pressure_plate"},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_roots"},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_sign"},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_slab"},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stairs"},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stem"},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_trapdoor"},{"id":"minecraft:crossbow","localizedName":"Crossbow","maxDamage":465,"maxStackSize":1,"unlocalizedName":"item.minecraft.crossbow"},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crying_obsidian"},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper"},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_slab"},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_stairs"},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone"},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone_slab"},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone"},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone_slab"},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.cyan_banner"},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_bed"},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_candle"},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_carpet"},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete"},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete_powder"},{"id":"minecraft:cyan_dye","localizedName":"Cyan Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cyan_dye"},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_glazed_terracotta"},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_shulker_box"},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass"},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass_pane"},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_terracotta"},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_wool"},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.damaged_anvil"},{"id":"minecraft:dandelion","localizedName":"Dandelion","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dandelion"},{"id":"minecraft:danger_pottery_sherd","localizedName":"Danger Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.danger_pottery_sherd"},{"id":"minecraft:dark_oak_boat","localizedName":"Dark Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_boat"},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_button"},{"id":"minecraft:dark_oak_chest_boat","localizedName":"Dark Oak Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_chest_boat"},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_door"},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence"},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence_gate"},{"id":"minecraft:dark_oak_hanging_sign","localizedName":"Dark Oak Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_hanging_sign"},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_leaves"},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_log"},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_planks"},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_pressure_plate"},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_sapling"},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_sign"},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_slab"},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_stairs"},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_trapdoor"},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_wood"},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine"},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_slab"},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_stairs"},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.daylight_detector"},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral"},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_block"},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_fan"},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral"},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_block"},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_fan"},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bush"},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral"},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_block"},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_fan"},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral"},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_block"},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_fan"},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral"},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_block"},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_fan"},{"id":"minecraft:debug_stick","localizedName":"Debug Stick","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.debug_stick"},{"id":"minecraft:decorated_pot","localizedName":"Decorated Pot","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.decorated_pot"},{"id":"minecraft:deepslate","localizedName":"Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate"},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_slab"},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_stairs"},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_wall"},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_bricks"},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_coal_ore"},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_copper_ore"},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_diamond_ore"},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_emerald_ore"},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_gold_ore"},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_iron_ore"},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_lapis_ore"},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_redstone_ore"},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_slab"},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_stairs"},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_wall"},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tiles"},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.detector_rail"},{"id":"minecraft:diamond","localizedName":"Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.diamond"},{"id":"minecraft:diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_axe"},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_block"},{"id":"minecraft:diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_boots"},{"id":"minecraft:diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_chestplate"},{"id":"minecraft:diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_helmet"},{"id":"minecraft:diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_hoe"},{"id":"minecraft:diamond_horse_armor","localizedName":"Diamond Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_horse_armor"},{"id":"minecraft:diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_leggings"},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_ore"},{"id":"minecraft:diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_pickaxe"},{"id":"minecraft:diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_shovel"},{"id":"minecraft:diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_sword"},{"id":"minecraft:diorite","localizedName":"Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite"},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_slab"},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_stairs"},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_wall"},{"id":"minecraft:dirt","localizedName":"Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt"},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt_path"},{"id":"minecraft:disc_fragment_5","localizedName":"Disc Fragment","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.disc_fragment_5"},{"id":"minecraft:dispenser","localizedName":"Dispenser","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dispenser"},{"id":"minecraft:dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dolphin_spawn_egg"},{"id":"minecraft:donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.donkey_spawn_egg"},{"id":"minecraft:dragon_breath","localizedName":"Dragon\u0027s Breath","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dragon_breath"},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_egg"},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_head"},{"id":"minecraft:dried_kelp","localizedName":"Dried Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dried_kelp"},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dried_kelp_block"},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dripstone_block"},{"id":"minecraft:dropper","localizedName":"Dropper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dropper"},{"id":"minecraft:drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.drowned_spawn_egg"},{"id":"minecraft:dune_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:echo_shard","localizedName":"Echo Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.echo_shard"},{"id":"minecraft:egg","localizedName":"Egg","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.egg"},{"id":"minecraft:elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.elder_guardian_spawn_egg"},{"id":"minecraft:elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1,"unlocalizedName":"item.minecraft.elytra"},{"id":"minecraft:emerald","localizedName":"Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.emerald"},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_block"},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_ore"},{"id":"minecraft:enchanted_book","localizedName":"Enchanted Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.enchanted_book"},{"id":"minecraft:enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enchanted_golden_apple"},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.enchanting_table"},{"id":"minecraft:end_crystal","localizedName":"End Crystal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.end_crystal"},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_portal_frame"},{"id":"minecraft:end_rod","localizedName":"End Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_rod"},{"id":"minecraft:end_stone","localizedName":"End Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone"},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_slab"},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_stairs"},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_wall"},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_bricks"},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ender_chest"},{"id":"minecraft:ender_dragon_spawn_egg","localizedName":"Ender Dragon Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ender_dragon_spawn_egg"},{"id":"minecraft:ender_eye","localizedName":"Eye of Ender","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ender_eye"},{"id":"minecraft:ender_pearl","localizedName":"Ender Pearl","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.ender_pearl"},{"id":"minecraft:enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enderman_spawn_egg"},{"id":"minecraft:endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.endermite_spawn_egg"},{"id":"minecraft:evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.evoker_spawn_egg"},{"id":"minecraft:experience_bottle","localizedName":"Bottle o\u0027 Enchanting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.experience_bottle"},{"id":"minecraft:explorer_pottery_sherd","localizedName":"Explorer Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.explorer_pottery_sherd"},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper"},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper"},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_slab"},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_stairs"},{"id":"minecraft:eye_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:farmland","localizedName":"Farmland","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.farmland"},{"id":"minecraft:feather","localizedName":"Feather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.feather"},{"id":"minecraft:fermented_spider_eye","localizedName":"Fermented Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fermented_spider_eye"},{"id":"minecraft:fern","localizedName":"Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fern"},{"id":"minecraft:filled_map","localizedName":"Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.filled_map"},{"id":"minecraft:fire_charge","localizedName":"Fire Charge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fire_charge"},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral"},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_block"},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_fan"},{"id":"minecraft:firework_rocket","localizedName":"Firework Rocket","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_rocket"},{"id":"minecraft:firework_star","localizedName":"Firework Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_star"},{"id":"minecraft:fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.fishing_rod"},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fletching_table"},{"id":"minecraft:flint","localizedName":"Flint","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.flint"},{"id":"minecraft:flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.flint_and_steel"},{"id":"minecraft:flower_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.flower_banner_pattern"},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flower_pot"},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea"},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea_leaves"},{"id":"minecraft:fox_spawn_egg","localizedName":"Fox Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fox_spawn_egg"},{"id":"minecraft:friend_pottery_sherd","localizedName":"Friend Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.friend_pottery_sherd"},{"id":"minecraft:frog_spawn_egg","localizedName":"Frog Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.frog_spawn_egg"},{"id":"minecraft:frogspawn","localizedName":"Frogspawn","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.frogspawn"},{"id":"minecraft:furnace","localizedName":"Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.furnace"},{"id":"minecraft:furnace_minecart","localizedName":"Minecart with Furnace","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.furnace_minecart"},{"id":"minecraft:ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_spawn_egg"},{"id":"minecraft:ghast_tear","localizedName":"Ghast Tear","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_tear"},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gilded_blackstone"},{"id":"minecraft:glass","localizedName":"Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass"},{"id":"minecraft:glass_bottle","localizedName":"Glass Bottle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glass_bottle"},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass_pane"},{"id":"minecraft:glistering_melon_slice","localizedName":"Glistering Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glistering_melon_slice"},{"id":"minecraft:globe_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.globe_banner_pattern"},{"id":"minecraft:glow_berries","localizedName":"Glow Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_berries"},{"id":"minecraft:glow_ink_sac","localizedName":"Glow Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_ink_sac"},{"id":"minecraft:glow_item_frame","localizedName":"Glow Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_item_frame"},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glow_lichen"},{"id":"minecraft:glow_squid_spawn_egg","localizedName":"Glow Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_squid_spawn_egg"},{"id":"minecraft:glowstone","localizedName":"Glowstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glowstone"},{"id":"minecraft:glowstone_dust","localizedName":"Glowstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glowstone_dust"},{"id":"minecraft:goat_horn","localizedName":"Goat Horn","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.goat_horn"},{"id":"minecraft:goat_spawn_egg","localizedName":"Goat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.goat_spawn_egg"},{"id":"minecraft:gold_block","localizedName":"Block of Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_block"},{"id":"minecraft:gold_ingot","localizedName":"Gold Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_ingot"},{"id":"minecraft:gold_nugget","localizedName":"Gold Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_nugget"},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_ore"},{"id":"minecraft:golden_apple","localizedName":"Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_apple"},{"id":"minecraft:golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_axe"},{"id":"minecraft:golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_boots"},{"id":"minecraft:golden_carrot","localizedName":"Golden Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_carrot"},{"id":"minecraft:golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_chestplate"},{"id":"minecraft:golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_helmet"},{"id":"minecraft:golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_hoe"},{"id":"minecraft:golden_horse_armor","localizedName":"Golden Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_horse_armor"},{"id":"minecraft:golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_leggings"},{"id":"minecraft:golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_pickaxe"},{"id":"minecraft:golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_shovel"},{"id":"minecraft:golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_sword"},{"id":"minecraft:granite","localizedName":"Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite"},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_slab"},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_stairs"},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_wall"},{"id":"minecraft:grass","localizedName":"Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass"},{"id":"minecraft:grass_block","localizedName":"Grass Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass_block"},{"id":"minecraft:gravel","localizedName":"Gravel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gravel"},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.gray_banner"},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_bed"},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_candle"},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_carpet"},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete"},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete_powder"},{"id":"minecraft:gray_dye","localizedName":"Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gray_dye"},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_glazed_terracotta"},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_shulker_box"},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass"},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass_pane"},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_terracotta"},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_wool"},{"id":"minecraft:green_banner","localizedName":"Green Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.green_banner"},{"id":"minecraft:green_bed","localizedName":"Green Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_bed"},{"id":"minecraft:green_candle","localizedName":"Green Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_candle"},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_carpet"},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete"},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete_powder"},{"id":"minecraft:green_dye","localizedName":"Green Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.green_dye"},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_glazed_terracotta"},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_shulker_box"},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass"},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass_pane"},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_terracotta"},{"id":"minecraft:green_wool","localizedName":"Green Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_wool"},{"id":"minecraft:grindstone","localizedName":"Grindstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grindstone"},{"id":"minecraft:guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.guardian_spawn_egg"},{"id":"minecraft:gunpowder","localizedName":"Gunpowder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gunpowder"},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hanging_roots"},{"id":"minecraft:hay_block","localizedName":"Hay Bale","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hay_block"},{"id":"minecraft:heart_of_the_sea","localizedName":"Heart of the Sea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.heart_of_the_sea"},{"id":"minecraft:heart_pottery_sherd","localizedName":"Heart Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.heart_pottery_sherd"},{"id":"minecraft:heartbreak_pottery_sherd","localizedName":"Heartbreak Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.heartbreak_pottery_sherd"},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate"},{"id":"minecraft:hoglin_spawn_egg","localizedName":"Hoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.hoglin_spawn_egg"},{"id":"minecraft:honey_block","localizedName":"Honey Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honey_block"},{"id":"minecraft:honey_bottle","localizedName":"Honey Bottle","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.honey_bottle"},{"id":"minecraft:honeycomb","localizedName":"Honeycomb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.honeycomb"},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honeycomb_block"},{"id":"minecraft:hopper","localizedName":"Hopper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hopper"},{"id":"minecraft:hopper_minecart","localizedName":"Minecart with Hopper","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.hopper_minecart"},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral"},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_block"},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_fan"},{"id":"minecraft:horse_spawn_egg","localizedName":"Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.horse_spawn_egg"},{"id":"minecraft:host_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:howl_pottery_sherd","localizedName":"Howl Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.howl_pottery_sherd"},{"id":"minecraft:husk_spawn_egg","localizedName":"Husk Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.husk_spawn_egg"},{"id":"minecraft:ice","localizedName":"Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ice"},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks"},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cobblestone"},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cracked_stone_bricks"},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_deepslate"},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_mossy_stone_bricks"},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone"},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone_bricks"},{"id":"minecraft:ink_sac","localizedName":"Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ink_sac"},{"id":"minecraft:iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_axe"},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_bars"},{"id":"minecraft:iron_block","localizedName":"Block of Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_block"},{"id":"minecraft:iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_boots"},{"id":"minecraft:iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_chestplate"},{"id":"minecraft:iron_door","localizedName":"Iron Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_door"},{"id":"minecraft:iron_golem_spawn_egg","localizedName":"Iron Golem Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_golem_spawn_egg"},{"id":"minecraft:iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_helmet"},{"id":"minecraft:iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_hoe"},{"id":"minecraft:iron_horse_armor","localizedName":"Iron Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_horse_armor"},{"id":"minecraft:iron_ingot","localizedName":"Iron Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_ingot"},{"id":"minecraft:iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_leggings"},{"id":"minecraft:iron_nugget","localizedName":"Iron Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_nugget"},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_ore"},{"id":"minecraft:iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_pickaxe"},{"id":"minecraft:iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_shovel"},{"id":"minecraft:iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_sword"},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_trapdoor"},{"id":"minecraft:item_frame","localizedName":"Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.item_frame"},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jack_o_lantern"},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jigsaw"},{"id":"minecraft:jukebox","localizedName":"Jukebox","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jukebox"},{"id":"minecraft:jungle_boat","localizedName":"Jungle Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_boat"},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_button"},{"id":"minecraft:jungle_chest_boat","localizedName":"Jungle Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_chest_boat"},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_door"},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence"},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence_gate"},{"id":"minecraft:jungle_hanging_sign","localizedName":"Jungle Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_hanging_sign"},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_leaves"},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_log"},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_planks"},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_pressure_plate"},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_sapling"},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_sign"},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_slab"},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_stairs"},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_trapdoor"},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_wood"},{"id":"minecraft:kelp","localizedName":"Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.kelp"},{"id":"minecraft:knowledge_book","localizedName":"Knowledge Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.knowledge_book"},{"id":"minecraft:ladder","localizedName":"Ladder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ladder"},{"id":"minecraft:lantern","localizedName":"Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lantern"},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_block"},{"id":"minecraft:lapis_lazuli","localizedName":"Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lapis_lazuli"},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_ore"},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_amethyst_bud"},{"id":"minecraft:large_fern","localizedName":"Large Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_fern"},{"id":"minecraft:lava_bucket","localizedName":"Lava Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lava_bucket"},{"id":"minecraft:lead","localizedName":"Lead","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lead"},{"id":"minecraft:leather","localizedName":"Leather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.leather"},{"id":"minecraft:leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_boots"},{"id":"minecraft:leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_chestplate"},{"id":"minecraft:leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_helmet"},{"id":"minecraft:leather_horse_armor","localizedName":"Leather Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_horse_armor"},{"id":"minecraft:leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_leggings"},{"id":"minecraft:lectern","localizedName":"Lectern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lectern"},{"id":"minecraft:lever","localizedName":"Lever","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lever"},{"id":"minecraft:light","localizedName":"Light","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light"},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_blue_banner"},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_bed"},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_candle"},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_carpet"},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete"},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete_powder"},{"id":"minecraft:light_blue_dye","localizedName":"Light Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_blue_dye"},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_glazed_terracotta"},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_shulker_box"},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass"},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass_pane"},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_terracotta"},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_wool"},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_gray_banner"},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_bed"},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_candle"},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_carpet"},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete"},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete_powder"},{"id":"minecraft:light_gray_dye","localizedName":"Light Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_gray_dye"},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_glazed_terracotta"},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_shulker_box"},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass"},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass_pane"},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_terracotta"},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_wool"},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_weighted_pressure_plate"},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lightning_rod"},{"id":"minecraft:lilac","localizedName":"Lilac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lilac"},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_of_the_valley"},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_pad"},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.lime_banner"},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_bed"},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_candle"},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_carpet"},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete"},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete_powder"},{"id":"minecraft:lime_dye","localizedName":"Lime Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lime_dye"},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_glazed_terracotta"},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_shulker_box"},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass"},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass_pane"},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_terracotta"},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_wool"},{"id":"minecraft:lingering_potion","localizedName":"Lingering Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lingering_potion.effect.water"},{"id":"minecraft:llama_spawn_egg","localizedName":"Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.llama_spawn_egg"},{"id":"minecraft:lodestone","localizedName":"Lodestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lodestone"},{"id":"minecraft:loom","localizedName":"Loom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.loom"},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.magenta_banner"},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_bed"},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_candle"},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_carpet"},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete"},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete_powder"},{"id":"minecraft:magenta_dye","localizedName":"Magenta Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magenta_dye"},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_glazed_terracotta"},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_shulker_box"},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass"},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass_pane"},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_terracotta"},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_wool"},{"id":"minecraft:magma_block","localizedName":"Magma Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magma_block"},{"id":"minecraft:magma_cream","localizedName":"Magma Cream","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cream"},{"id":"minecraft:magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cube_spawn_egg"},{"id":"minecraft:mangrove_boat","localizedName":"Mangrove Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mangrove_boat"},{"id":"minecraft:mangrove_button","localizedName":"Mangrove Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_button"},{"id":"minecraft:mangrove_chest_boat","localizedName":"Mangrove Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mangrove_chest_boat"},{"id":"minecraft:mangrove_door","localizedName":"Mangrove Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_door"},{"id":"minecraft:mangrove_fence","localizedName":"Mangrove Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_fence"},{"id":"minecraft:mangrove_fence_gate","localizedName":"Mangrove Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_fence_gate"},{"id":"minecraft:mangrove_hanging_sign","localizedName":"Mangrove Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.mangrove_hanging_sign"},{"id":"minecraft:mangrove_leaves","localizedName":"Mangrove Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_leaves"},{"id":"minecraft:mangrove_log","localizedName":"Mangrove Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_log"},{"id":"minecraft:mangrove_planks","localizedName":"Mangrove Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_planks"},{"id":"minecraft:mangrove_pressure_plate","localizedName":"Mangrove Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_pressure_plate"},{"id":"minecraft:mangrove_propagule","localizedName":"Mangrove Propagule","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_propagule"},{"id":"minecraft:mangrove_roots","localizedName":"Mangrove Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_roots"},{"id":"minecraft:mangrove_sign","localizedName":"Mangrove Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.mangrove_sign"},{"id":"minecraft:mangrove_slab","localizedName":"Mangrove Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_slab"},{"id":"minecraft:mangrove_stairs","localizedName":"Mangrove Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_stairs"},{"id":"minecraft:mangrove_trapdoor","localizedName":"Mangrove Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_trapdoor"},{"id":"minecraft:mangrove_wood","localizedName":"Mangrove Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_wood"},{"id":"minecraft:map","localizedName":"Empty Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.map"},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.medium_amethyst_bud"},{"id":"minecraft:melon","localizedName":"Melon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.melon"},{"id":"minecraft:melon_seeds","localizedName":"Melon Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_seeds"},{"id":"minecraft:melon_slice","localizedName":"Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_slice"},{"id":"minecraft:milk_bucket","localizedName":"Milk Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.milk_bucket"},{"id":"minecraft:minecart","localizedName":"Minecart","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.minecart"},{"id":"minecraft:miner_pottery_sherd","localizedName":"Miner Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.miner_pottery_sherd"},{"id":"minecraft:mojang_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mojang_banner_pattern"},{"id":"minecraft:mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mooshroom_spawn_egg"},{"id":"minecraft:moss_block","localizedName":"Moss Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.moss_block"},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.moss_carpet"},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone"},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_slab"},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_stairs"},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_wall"},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_slab"},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_stairs"},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_wall"},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_bricks"},{"id":"minecraft:mourner_pottery_sherd","localizedName":"Mourner Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mourner_pottery_sherd"},{"id":"minecraft:mud","localizedName":"Mud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud"},{"id":"minecraft:mud_brick_slab","localizedName":"Mud Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_slab"},{"id":"minecraft:mud_brick_stairs","localizedName":"Mud Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_stairs"},{"id":"minecraft:mud_brick_wall","localizedName":"Mud Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_wall"},{"id":"minecraft:mud_bricks","localizedName":"Mud Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_bricks"},{"id":"minecraft:muddy_mangrove_roots","localizedName":"Muddy Mangrove Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.muddy_mangrove_roots"},{"id":"minecraft:mule_spawn_egg","localizedName":"Mule Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mule_spawn_egg"},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mushroom_stem"},{"id":"minecraft:mushroom_stew","localizedName":"Mushroom Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mushroom_stew"},{"id":"minecraft:music_disc_11","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_11"},{"id":"minecraft:music_disc_13","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_13"},{"id":"minecraft:music_disc_5","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_5"},{"id":"minecraft:music_disc_blocks","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_blocks"},{"id":"minecraft:music_disc_cat","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_cat"},{"id":"minecraft:music_disc_chirp","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_chirp"},{"id":"minecraft:music_disc_far","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_far"},{"id":"minecraft:music_disc_mall","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mall"},{"id":"minecraft:music_disc_mellohi","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mellohi"},{"id":"minecraft:music_disc_otherside","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_otherside"},{"id":"minecraft:music_disc_pigstep","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_pigstep"},{"id":"minecraft:music_disc_relic","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_relic"},{"id":"minecraft:music_disc_stal","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_stal"},{"id":"minecraft:music_disc_strad","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_strad"},{"id":"minecraft:music_disc_wait","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_wait"},{"id":"minecraft:music_disc_ward","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_ward"},{"id":"minecraft:mutton","localizedName":"Raw Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mutton"},{"id":"minecraft:mycelium","localizedName":"Mycelium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mycelium"},{"id":"minecraft:name_tag","localizedName":"Name Tag","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.name_tag"},{"id":"minecraft:nautilus_shell","localizedName":"Nautilus Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nautilus_shell"},{"id":"minecraft:nether_brick","localizedName":"Nether Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_brick"},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_fence"},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_slab"},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_stairs"},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_wall"},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_bricks"},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_gold_ore"},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_quartz_ore"},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_sprouts"},{"id":"minecraft:nether_star","localizedName":"Nether Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_star"},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_wart"},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_wart_block"},{"id":"minecraft:netherite_axe","localizedName":"Netherite Axe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_axe"},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherite_block"},{"id":"minecraft:netherite_boots","localizedName":"Netherite Boots","maxDamage":481,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_boots"},{"id":"minecraft:netherite_chestplate","localizedName":"Netherite Chestplate","maxDamage":592,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_chestplate"},{"id":"minecraft:netherite_helmet","localizedName":"Netherite Helmet","maxDamage":407,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_helmet"},{"id":"minecraft:netherite_hoe","localizedName":"Netherite Hoe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_hoe"},{"id":"minecraft:netherite_ingot","localizedName":"Netherite Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_ingot"},{"id":"minecraft:netherite_leggings","localizedName":"Netherite Leggings","maxDamage":555,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_leggings"},{"id":"minecraft:netherite_pickaxe","localizedName":"Netherite Pickaxe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_pickaxe"},{"id":"minecraft:netherite_scrap","localizedName":"Netherite Scrap","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_scrap"},{"id":"minecraft:netherite_shovel","localizedName":"Netherite Shovel","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_shovel"},{"id":"minecraft:netherite_sword","localizedName":"Netherite Sword","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_sword"},{"id":"minecraft:netherite_upgrade_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:netherrack","localizedName":"Netherrack","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherrack"},{"id":"minecraft:note_block","localizedName":"Note Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.note_block"},{"id":"minecraft:oak_boat","localizedName":"Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.oak_boat"},{"id":"minecraft:oak_button","localizedName":"Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_button"},{"id":"minecraft:oak_chest_boat","localizedName":"Oak Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.oak_chest_boat"},{"id":"minecraft:oak_door","localizedName":"Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_door"},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence"},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence_gate"},{"id":"minecraft:oak_hanging_sign","localizedName":"Oak Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.oak_hanging_sign"},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_leaves"},{"id":"minecraft:oak_log","localizedName":"Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_log"},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_planks"},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_pressure_plate"},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_sapling"},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.oak_sign"},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_slab"},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_stairs"},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_trapdoor"},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_wood"},{"id":"minecraft:observer","localizedName":"Observer","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.observer"},{"id":"minecraft:obsidian","localizedName":"Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.obsidian"},{"id":"minecraft:ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ocelot_spawn_egg"},{"id":"minecraft:ochre_froglight","localizedName":"Ochre Froglight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ochre_froglight"},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.orange_banner"},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_bed"},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_candle"},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_carpet"},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete"},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete_powder"},{"id":"minecraft:orange_dye","localizedName":"Orange Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.orange_dye"},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_glazed_terracotta"},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_shulker_box"},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass"},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass_pane"},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_terracotta"},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_tulip"},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_wool"},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxeye_daisy"},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper"},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper"},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_slab"},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_stairs"},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.packed_ice"},{"id":"minecraft:packed_mud","localizedName":"Packed Mud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.packed_mud"},{"id":"minecraft:painting","localizedName":"Painting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.painting"},{"id":"minecraft:panda_spawn_egg","localizedName":"Panda Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.panda_spawn_egg"},{"id":"minecraft:paper","localizedName":"Paper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.paper"},{"id":"minecraft:parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.parrot_spawn_egg"},{"id":"minecraft:pearlescent_froglight","localizedName":"Pearlescent Froglight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pearlescent_froglight"},{"id":"minecraft:peony","localizedName":"Peony","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.peony"},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.petrified_oak_slab"},{"id":"minecraft:phantom_membrane","localizedName":"Phantom Membrane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_membrane"},{"id":"minecraft:phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_spawn_egg"},{"id":"minecraft:pig_spawn_egg","localizedName":"Pig Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pig_spawn_egg"},{"id":"minecraft:piglin_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.piglin_banner_pattern"},{"id":"minecraft:piglin_brute_spawn_egg","localizedName":"Piglin Brute Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_brute_spawn_egg"},{"id":"minecraft:piglin_head","localizedName":"Piglin Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.piglin_head"},{"id":"minecraft:piglin_spawn_egg","localizedName":"Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_spawn_egg"},{"id":"minecraft:pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pillager_spawn_egg"},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.pink_banner"},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_bed"},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_candle"},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_carpet"},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete"},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete_powder"},{"id":"minecraft:pink_dye","localizedName":"Pink Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pink_dye"},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_glazed_terracotta"},{"id":"minecraft:pink_petals","localizedName":"Pink Petals","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_petals"},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_shulker_box"},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass"},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass_pane"},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_terracotta"},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_tulip"},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_wool"},{"id":"minecraft:piston","localizedName":"Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.piston"},{"id":"minecraft:pitcher_plant","localizedName":"Pitcher Plant","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pitcher_plant"},{"id":"minecraft:pitcher_pod","localizedName":"Pitcher Pod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pitcher_pod"},{"id":"minecraft:player_head","localizedName":"Player Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.player_head"},{"id":"minecraft:plenty_pottery_sherd","localizedName":"Plenty Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.plenty_pottery_sherd"},{"id":"minecraft:podzol","localizedName":"Podzol","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.podzol"},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pointed_dripstone"},{"id":"minecraft:poisonous_potato","localizedName":"Poisonous Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.poisonous_potato"},{"id":"minecraft:polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.polar_bear_spawn_egg"},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite"},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_slab"},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_stairs"},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_basalt"},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone"},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_slab"},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_stairs"},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_wall"},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_bricks"},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_button"},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_pressure_plate"},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_slab"},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_stairs"},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_wall"},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate"},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_slab"},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_stairs"},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_wall"},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite"},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_slab"},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_stairs"},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite"},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_slab"},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_stairs"},{"id":"minecraft:popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.popped_chorus_fruit"},{"id":"minecraft:poppy","localizedName":"Poppy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.poppy"},{"id":"minecraft:porkchop","localizedName":"Raw Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.porkchop"},{"id":"minecraft:potato","localizedName":"Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.potato"},{"id":"minecraft:potion","localizedName":"Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.potion.effect.water"},{"id":"minecraft:powder_snow_bucket","localizedName":"Powder Snow Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.powder_snow_bucket"},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.powered_rail"},{"id":"minecraft:prismarine","localizedName":"Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine"},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_slab"},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_stairs"},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_bricks"},{"id":"minecraft:prismarine_crystals","localizedName":"Prismarine Crystals","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_crystals"},{"id":"minecraft:prismarine_shard","localizedName":"Prismarine Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_shard"},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_slab"},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_stairs"},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_wall"},{"id":"minecraft:prize_pottery_sherd","localizedName":"Prize Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prize_pottery_sherd"},{"id":"minecraft:pufferfish","localizedName":"Pufferfish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish"},{"id":"minecraft:pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.pufferfish_bucket"},{"id":"minecraft:pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish_spawn_egg"},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pumpkin"},{"id":"minecraft:pumpkin_pie","localizedName":"Pumpkin Pie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_pie"},{"id":"minecraft:pumpkin_seeds","localizedName":"Pumpkin Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_seeds"},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.purple_banner"},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_bed"},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_candle"},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_carpet"},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete"},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete_powder"},{"id":"minecraft:purple_dye","localizedName":"Purple Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.purple_dye"},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_glazed_terracotta"},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_shulker_box"},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass"},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass_pane"},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_terracotta"},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_wool"},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_block"},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_pillar"},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_slab"},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_stairs"},{"id":"minecraft:quartz","localizedName":"Nether Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.quartz"},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_block"},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_bricks"},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_pillar"},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_slab"},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_stairs"},{"id":"minecraft:rabbit","localizedName":"Raw Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit"},{"id":"minecraft:rabbit_foot","localizedName":"Rabbit\u0027s Foot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_foot"},{"id":"minecraft:rabbit_hide","localizedName":"Rabbit Hide","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_hide"},{"id":"minecraft:rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_spawn_egg"},{"id":"minecraft:rabbit_stew","localizedName":"Rabbit Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.rabbit_stew"},{"id":"minecraft:rail","localizedName":"Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rail"},{"id":"minecraft:raiser_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ravager_spawn_egg"},{"id":"minecraft:raw_copper","localizedName":"Raw Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_copper"},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_copper_block"},{"id":"minecraft:raw_gold","localizedName":"Raw Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_gold"},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_gold_block"},{"id":"minecraft:raw_iron","localizedName":"Raw Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_iron"},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_iron_block"},{"id":"minecraft:recovery_compass","localizedName":"Recovery Compass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.recovery_compass"},{"id":"minecraft:red_banner","localizedName":"Red Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.red_banner"},{"id":"minecraft:red_bed","localizedName":"Red Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_bed"},{"id":"minecraft:red_candle","localizedName":"Red Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_candle"},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_carpet"},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete"},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete_powder"},{"id":"minecraft:red_dye","localizedName":"Red Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.red_dye"},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_glazed_terracotta"},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom"},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom_block"},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_slab"},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_stairs"},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_wall"},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_bricks"},{"id":"minecraft:red_sand","localizedName":"Red Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sand"},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone"},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_slab"},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_stairs"},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_wall"},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_shulker_box"},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass"},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass_pane"},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_terracotta"},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_tulip"},{"id":"minecraft:red_wool","localizedName":"Red Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_wool"},{"id":"minecraft:redstone","localizedName":"Redstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.redstone"},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_block"},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_lamp"},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_ore"},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_torch"},{"id":"minecraft:reinforced_deepslate","localizedName":"Reinforced Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.reinforced_deepslate"},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeater"},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeating_command_block"},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.respawn_anchor"},{"id":"minecraft:rib_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rooted_dirt"},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rose_bush"},{"id":"minecraft:rotten_flesh","localizedName":"Rotten Flesh","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rotten_flesh"},{"id":"minecraft:saddle","localizedName":"Saddle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.saddle"},{"id":"minecraft:salmon","localizedName":"Raw Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon"},{"id":"minecraft:salmon_bucket","localizedName":"Bucket of Salmon","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.salmon_bucket"},{"id":"minecraft:salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon_spawn_egg"},{"id":"minecraft:sand","localizedName":"Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sand"},{"id":"minecraft:sandstone","localizedName":"Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone"},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_slab"},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_stairs"},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_wall"},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.scaffolding"},{"id":"minecraft:sculk","localizedName":"Sculk","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk"},{"id":"minecraft:sculk_catalyst","localizedName":"Sculk Catalyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_catalyst"},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_sensor"},{"id":"minecraft:sculk_shrieker","localizedName":"Sculk Shrieker","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_shrieker"},{"id":"minecraft:sculk_vein","localizedName":"Sculk Vein","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_vein"},{"id":"minecraft:scute","localizedName":"Scute","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.scute"},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_lantern"},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_pickle"},{"id":"minecraft:seagrass","localizedName":"Seagrass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.seagrass"},{"id":"minecraft:sentry_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:shaper_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:sheaf_pottery_sherd","localizedName":"Sheaf Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sheaf_pottery_sherd"},{"id":"minecraft:shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1,"unlocalizedName":"item.minecraft.shears"},{"id":"minecraft:sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sheep_spawn_egg"},{"id":"minecraft:shelter_pottery_sherd","localizedName":"Shelter Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shelter_pottery_sherd"},{"id":"minecraft:shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1,"unlocalizedName":"item.minecraft.shield"},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.shroomlight"},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.shulker_box"},{"id":"minecraft:shulker_shell","localizedName":"Shulker Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_shell"},{"id":"minecraft:shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_spawn_egg"},{"id":"minecraft:silence_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.silverfish_spawn_egg"},{"id":"minecraft:skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg"},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.skeleton_skull"},{"id":"minecraft:skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_spawn_egg"},{"id":"minecraft:skull_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.skull_banner_pattern"},{"id":"minecraft:skull_pottery_sherd","localizedName":"Skull Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skull_pottery_sherd"},{"id":"minecraft:slime_ball","localizedName":"Slimeball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_ball"},{"id":"minecraft:slime_block","localizedName":"Slime Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.slime_block"},{"id":"minecraft:slime_spawn_egg","localizedName":"Slime Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_spawn_egg"},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.small_amethyst_bud"},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.small_dripleaf"},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smithing_table"},{"id":"minecraft:smoker","localizedName":"Smoker","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smoker"},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_basalt"},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz"},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_slab"},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_stairs"},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone"},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_slab"},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs"},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone"},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_slab"},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_stairs"},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone"},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone_slab"},{"id":"minecraft:sniffer_egg","localizedName":"Sniffer Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sniffer_egg"},{"id":"minecraft:sniffer_spawn_egg","localizedName":"Sniffer Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sniffer_spawn_egg"},{"id":"minecraft:snort_pottery_sherd","localizedName":"Snort Pottery Sherd","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.snort_pottery_sherd"},{"id":"minecraft:snout_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:snow","localizedName":"Snow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow"},{"id":"minecraft:snow_block","localizedName":"Snow Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow_block"},{"id":"minecraft:snow_golem_spawn_egg","localizedName":"Snow Golem Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.snow_golem_spawn_egg"},{"id":"minecraft:snowball","localizedName":"Snowball","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.snowball"},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_campfire"},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_lantern"},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_sand"},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_soil"},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_torch"},{"id":"minecraft:spawner","localizedName":"Monster Spawner","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spawner"},{"id":"minecraft:spectral_arrow","localizedName":"Spectral Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spectral_arrow"},{"id":"minecraft:spider_eye","localizedName":"Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_eye"},{"id":"minecraft:spider_spawn_egg","localizedName":"Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_spawn_egg"},{"id":"minecraft:spire_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:splash_potion","localizedName":"Splash Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.splash_potion.effect.water"},{"id":"minecraft:sponge","localizedName":"Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sponge"},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spore_blossom"},{"id":"minecraft:spruce_boat","localizedName":"Spruce Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_boat"},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_button"},{"id":"minecraft:spruce_chest_boat","localizedName":"Spruce Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_chest_boat"},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_door"},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence"},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence_gate"},{"id":"minecraft:spruce_hanging_sign","localizedName":"Spruce Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_hanging_sign"},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_leaves"},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_log"},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_planks"},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_pressure_plate"},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_sapling"},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_sign"},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_slab"},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_stairs"},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_trapdoor"},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_wood"},{"id":"minecraft:spyglass","localizedName":"Spyglass","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spyglass"},{"id":"minecraft:squid_spawn_egg","localizedName":"Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.squid_spawn_egg"},{"id":"minecraft:stick","localizedName":"Stick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stick"},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sticky_piston"},{"id":"minecraft:stone","localizedName":"Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone"},{"id":"minecraft:stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_axe"},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_slab"},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_stairs"},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_wall"},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_bricks"},{"id":"minecraft:stone_button","localizedName":"Stone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_button"},{"id":"minecraft:stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_hoe"},{"id":"minecraft:stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_pickaxe"},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_pressure_plate"},{"id":"minecraft:stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_shovel"},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_slab"},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_stairs"},{"id":"minecraft:stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_sword"},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stonecutter"},{"id":"minecraft:stray_spawn_egg","localizedName":"Stray Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stray_spawn_egg"},{"id":"minecraft:strider_spawn_egg","localizedName":"Strider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.strider_spawn_egg"},{"id":"minecraft:string","localizedName":"String","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.string"},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_log"},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_wood"},{"id":"minecraft:stripped_bamboo_block","localizedName":"Block of Stripped Bamboo","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_bamboo_block"},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_log"},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_wood"},{"id":"minecraft:stripped_cherry_log","localizedName":"Stripped Cherry Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_cherry_log"},{"id":"minecraft:stripped_cherry_wood","localizedName":"Stripped Cherry Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_cherry_wood"},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_hyphae"},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_stem"},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_log"},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_wood"},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_log"},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_wood"},{"id":"minecraft:stripped_mangrove_log","localizedName":"Stripped Mangrove Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_mangrove_log"},{"id":"minecraft:stripped_mangrove_wood","localizedName":"Stripped Mangrove Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_mangrove_wood"},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_log"},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_wood"},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_log"},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_wood"},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_hyphae"},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_stem"},{"id":"minecraft:structure_block","localizedName":"Structure Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_block"},{"id":"minecraft:structure_void","localizedName":"Structure Void","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_void"},{"id":"minecraft:sugar","localizedName":"Sugar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sugar"},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sugar_cane"},{"id":"minecraft:sunflower","localizedName":"Sunflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sunflower"},{"id":"minecraft:suspicious_gravel","localizedName":"Suspicious Gravel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.suspicious_gravel"},{"id":"minecraft:suspicious_sand","localizedName":"Suspicious Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.suspicious_sand"},{"id":"minecraft:suspicious_stew","localizedName":"Suspicious Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.suspicious_stew"},{"id":"minecraft:sweet_berries","localizedName":"Sweet Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sweet_berries"},{"id":"minecraft:tadpole_bucket","localizedName":"Bucket of Tadpole","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tadpole_bucket"},{"id":"minecraft:tadpole_spawn_egg","localizedName":"Tadpole Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tadpole_spawn_egg"},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tall_grass"},{"id":"minecraft:target","localizedName":"Target","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.target"},{"id":"minecraft:terracotta","localizedName":"Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.terracotta"},{"id":"minecraft:tide_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tinted_glass"},{"id":"minecraft:tipped_arrow","localizedName":"Arrow of Poison","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tipped_arrow.effect.poison"},{"id":"minecraft:tnt","localizedName":"TNT","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tnt"},{"id":"minecraft:tnt_minecart","localizedName":"Minecart with TNT","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tnt_minecart"},{"id":"minecraft:torch","localizedName":"Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.torch"},{"id":"minecraft:torchflower","localizedName":"Torchflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.torchflower"},{"id":"minecraft:torchflower_seeds","localizedName":"Torchflower Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.torchflower_seeds"},{"id":"minecraft:totem_of_undying","localizedName":"Totem of Undying","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.totem_of_undying"},{"id":"minecraft:trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.trader_llama_spawn_egg"},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.trapped_chest"},{"id":"minecraft:trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.trident"},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tripwire_hook"},{"id":"minecraft:tropical_fish","localizedName":"Tropical Fish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish"},{"id":"minecraft:tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tropical_fish_bucket"},{"id":"minecraft:tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish_spawn_egg"},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral"},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_block"},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_fan"},{"id":"minecraft:tuff","localizedName":"Tuff","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tuff"},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.turtle_egg"},{"id":"minecraft:turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1,"unlocalizedName":"item.minecraft.turtle_helmet"},{"id":"minecraft:turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_spawn_egg"},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.twisting_vines"},{"id":"minecraft:verdant_froglight","localizedName":"Verdant Froglight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.verdant_froglight"},{"id":"minecraft:vex_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:vex_spawn_egg","localizedName":"Vex Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vex_spawn_egg"},{"id":"minecraft:villager_spawn_egg","localizedName":"Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.villager_spawn_egg"},{"id":"minecraft:vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vindicator_spawn_egg"},{"id":"minecraft:vine","localizedName":"Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.vine"},{"id":"minecraft:wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wandering_trader_spawn_egg"},{"id":"minecraft:ward_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:warden_spawn_egg","localizedName":"Warden Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.warden_spawn_egg"},{"id":"minecraft:warped_button","localizedName":"Warped Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_button"},{"id":"minecraft:warped_door","localizedName":"Warped Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_door"},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence"},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence_gate"},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fungus"},{"id":"minecraft:warped_fungus_on_a_stick","localizedName":"Warped Fungus on a Stick","maxDamage":100,"maxStackSize":1,"unlocalizedName":"item.minecraft.warped_fungus_on_a_stick"},{"id":"minecraft:warped_hanging_sign","localizedName":"Warped Hanging Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.warped_hanging_sign"},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_hyphae"},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_nylium"},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_planks"},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_pressure_plate"},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_roots"},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.warped_sign"},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_slab"},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stairs"},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stem"},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_trapdoor"},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_wart_block"},{"id":"minecraft:water_bucket","localizedName":"Water Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.water_bucket"},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_block"},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper"},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_slab"},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_stairs"},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper"},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper"},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_slab"},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_stairs"},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper"},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper"},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_slab"},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_stairs"},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper"},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper"},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_slab"},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_stairs"},{"id":"minecraft:wayfinder_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper"},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper"},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_slab"},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_stairs"},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weeping_vines"},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wet_sponge"},{"id":"minecraft:wheat","localizedName":"Wheat","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat"},{"id":"minecraft:wheat_seeds","localizedName":"Wheat Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat_seeds"},{"id":"minecraft:white_banner","localizedName":"White Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.white_banner"},{"id":"minecraft:white_bed","localizedName":"White Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_bed"},{"id":"minecraft:white_candle","localizedName":"White Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_candle"},{"id":"minecraft:white_carpet","localizedName":"White Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_carpet"},{"id":"minecraft:white_concrete","localizedName":"White Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete"},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete_powder"},{"id":"minecraft:white_dye","localizedName":"White Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.white_dye"},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_glazed_terracotta"},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_shulker_box"},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass"},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass_pane"},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_terracotta"},{"id":"minecraft:white_tulip","localizedName":"White Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_tulip"},{"id":"minecraft:white_wool","localizedName":"White Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_wool"},{"id":"minecraft:wild_armor_trim_smithing_template","localizedName":"Smithing Template","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.smithing_template"},{"id":"minecraft:witch_spawn_egg","localizedName":"Witch Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.witch_spawn_egg"},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_rose"},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_skeleton_skull"},{"id":"minecraft:wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg"},{"id":"minecraft:wither_spawn_egg","localizedName":"Wither Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wither_spawn_egg"},{"id":"minecraft:wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wolf_spawn_egg"},{"id":"minecraft:wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_axe"},{"id":"minecraft:wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_hoe"},{"id":"minecraft:wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_pickaxe"},{"id":"minecraft:wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_shovel"},{"id":"minecraft:wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_sword"},{"id":"minecraft:writable_book","localizedName":"Book and Quill","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.writable_book"},{"id":"minecraft:written_book","localizedName":"Written Book","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.written_book"},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.yellow_banner"},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_bed"},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_candle"},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_carpet"},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete"},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete_powder"},{"id":"minecraft:yellow_dye","localizedName":"Yellow Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.yellow_dye"},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_glazed_terracotta"},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_shulker_box"},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass"},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass_pane"},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_terracotta"},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_wool"},{"id":"minecraft:zoglin_spawn_egg","localizedName":"Zoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zoglin_spawn_egg"},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.zombie_head"},{"id":"minecraft:zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_horse_spawn_egg"},{"id":"minecraft:zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_spawn_egg"},{"id":"minecraft:zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_villager_spawn_egg"},{"id":"minecraft:zombified_piglin_spawn_egg","localizedName":"Zombified Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombified_piglin_spawn_egg"}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/items.json b/src/main/resources/com/sk89q/worldedit/world/registry/items.json new file mode 100644 index 0000000..5c58888 --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/items.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_boat","localizedName":"Acacia Boat"},{"id":"minecraft:acacia_button","localizedName":"Air"},{"id":"minecraft:acacia_door","localizedName":"Air"},{"id":"minecraft:acacia_fence","localizedName":"Air"},{"id":"minecraft:acacia_fence_gate","localizedName":"Air"},{"id":"minecraft:acacia_leaves","localizedName":"Air"},{"id":"minecraft:acacia_log","localizedName":"Air"},{"id":"minecraft:acacia_planks","localizedName":"Air"},{"id":"minecraft:acacia_pressure_plate","localizedName":"Air"},{"id":"minecraft:acacia_sapling","localizedName":"Air"},{"id":"minecraft:acacia_slab","localizedName":"Air"},{"id":"minecraft:acacia_stairs","localizedName":"Air"},{"id":"minecraft:acacia_trapdoor","localizedName":"Air"},{"id":"minecraft:acacia_wood","localizedName":"Air"},{"id":"minecraft:activator_rail","localizedName":"Air"},{"id":"minecraft:air","localizedName":"Air"},{"id":"minecraft:allium","localizedName":"Air"},{"id":"minecraft:andesite","localizedName":"Air"},{"id":"minecraft:anvil","localizedName":"Air"},{"id":"minecraft:apple","localizedName":"Apple"},{"id":"minecraft:armor_stand","localizedName":"Armor Stand"},{"id":"minecraft:arrow","localizedName":"Arrow"},{"id":"minecraft:azure_bluet","localizedName":"Air"},{"id":"minecraft:baked_potato","localizedName":"Baked Potato"},{"id":"minecraft:barrier","localizedName":"Air"},{"id":"minecraft:bat_spawn_egg","localizedName":"Bat Spawn Egg"},{"id":"minecraft:beacon","localizedName":"Air"},{"id":"minecraft:bedrock","localizedName":"Air"},{"id":"minecraft:beef","localizedName":"Raw Beef"},{"id":"minecraft:beetroot","localizedName":"Beetroot"},{"id":"minecraft:beetroot_seeds","localizedName":"Beetroot Seeds"},{"id":"minecraft:beetroot_soup","localizedName":"Beetroot Soup"},{"id":"minecraft:birch_boat","localizedName":"Birch Boat"},{"id":"minecraft:birch_button","localizedName":"Air"},{"id":"minecraft:birch_door","localizedName":"Air"},{"id":"minecraft:birch_fence","localizedName":"Air"},{"id":"minecraft:birch_fence_gate","localizedName":"Air"},{"id":"minecraft:birch_leaves","localizedName":"Air"},{"id":"minecraft:birch_log","localizedName":"Air"},{"id":"minecraft:birch_planks","localizedName":"Air"},{"id":"minecraft:birch_pressure_plate","localizedName":"Air"},{"id":"minecraft:birch_sapling","localizedName":"Air"},{"id":"minecraft:birch_slab","localizedName":"Air"},{"id":"minecraft:birch_stairs","localizedName":"Air"},{"id":"minecraft:birch_trapdoor","localizedName":"Air"},{"id":"minecraft:birch_wood","localizedName":"Air"},{"id":"minecraft:black_banner","localizedName":"Air"},{"id":"minecraft:black_bed","localizedName":"Air"},{"id":"minecraft:black_carpet","localizedName":"Air"},{"id":"minecraft:black_concrete","localizedName":"Air"},{"id":"minecraft:black_concrete_powder","localizedName":"Air"},{"id":"minecraft:black_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:black_shulker_box","localizedName":"Air"},{"id":"minecraft:black_stained_glass","localizedName":"Air"},{"id":"minecraft:black_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:black_terracotta","localizedName":"Air"},{"id":"minecraft:black_wool","localizedName":"Air"},{"id":"minecraft:blaze_powder","localizedName":"Blaze Powder"},{"id":"minecraft:blaze_rod","localizedName":"Blaze Rod"},{"id":"minecraft:blaze_spawn_egg","localizedName":"Blaze Spawn Egg"},{"id":"minecraft:blue_banner","localizedName":"Air"},{"id":"minecraft:blue_bed","localizedName":"Air"},{"id":"minecraft:blue_carpet","localizedName":"Air"},{"id":"minecraft:blue_concrete","localizedName":"Air"},{"id":"minecraft:blue_concrete_powder","localizedName":"Air"},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:blue_ice","localizedName":"Air"},{"id":"minecraft:blue_orchid","localizedName":"Air"},{"id":"minecraft:blue_shulker_box","localizedName":"Air"},{"id":"minecraft:blue_stained_glass","localizedName":"Air"},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:blue_terracotta","localizedName":"Air"},{"id":"minecraft:blue_wool","localizedName":"Air"},{"id":"minecraft:bone","localizedName":"Bone"},{"id":"minecraft:bone_block","localizedName":"Air"},{"id":"minecraft:bone_meal","localizedName":"Bone Meal"},{"id":"minecraft:book","localizedName":"Book"},{"id":"minecraft:bookshelf","localizedName":"Air"},{"id":"minecraft:bow","localizedName":"Bow"},{"id":"minecraft:bowl","localizedName":"Bowl"},{"id":"minecraft:brain_coral","localizedName":"Air"},{"id":"minecraft:brain_coral_block","localizedName":"Air"},{"id":"minecraft:brain_coral_fan","localizedName":"Air"},{"id":"minecraft:bread","localizedName":"Bread"},{"id":"minecraft:brewing_stand","localizedName":"Air"},{"id":"minecraft:brick","localizedName":"Brick"},{"id":"minecraft:brick_slab","localizedName":"Air"},{"id":"minecraft:brick_stairs","localizedName":"Air"},{"id":"minecraft:bricks","localizedName":"Air"},{"id":"minecraft:brown_banner","localizedName":"Air"},{"id":"minecraft:brown_bed","localizedName":"Air"},{"id":"minecraft:brown_carpet","localizedName":"Air"},{"id":"minecraft:brown_concrete","localizedName":"Air"},{"id":"minecraft:brown_concrete_powder","localizedName":"Air"},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:brown_mushroom","localizedName":"Air"},{"id":"minecraft:brown_mushroom_block","localizedName":"Air"},{"id":"minecraft:brown_shulker_box","localizedName":"Air"},{"id":"minecraft:brown_stained_glass","localizedName":"Air"},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:brown_terracotta","localizedName":"Air"},{"id":"minecraft:brown_wool","localizedName":"Air"},{"id":"minecraft:bubble_coral","localizedName":"Air"},{"id":"minecraft:bubble_coral_block","localizedName":"Air"},{"id":"minecraft:bubble_coral_fan","localizedName":"Air"},{"id":"minecraft:bucket","localizedName":"Bucket"},{"id":"minecraft:cactus","localizedName":"Air"},{"id":"minecraft:cactus_green","localizedName":"Cactus Green"},{"id":"minecraft:cake","localizedName":"Air"},{"id":"minecraft:carrot","localizedName":"Carrot"},{"id":"minecraft:carrot_on_a_stick","localizedName":"Carrot on a Stick"},{"id":"minecraft:carved_pumpkin","localizedName":"Air"},{"id":"minecraft:cauldron","localizedName":"Air"},{"id":"minecraft:cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg"},{"id":"minecraft:chain_command_block","localizedName":"Air"},{"id":"minecraft:chainmail_boots","localizedName":"Chainmail Boots"},{"id":"minecraft:chainmail_chestplate","localizedName":"Chainmail Chestplate"},{"id":"minecraft:chainmail_helmet","localizedName":"Chainmail Helmet"},{"id":"minecraft:chainmail_leggings","localizedName":"Chainmail Leggings"},{"id":"minecraft:charcoal","localizedName":"Charcoal"},{"id":"minecraft:chest","localizedName":"Air"},{"id":"minecraft:chest_minecart","localizedName":"Minecart with Chest"},{"id":"minecraft:chicken","localizedName":"Raw Chicken"},{"id":"minecraft:chicken_spawn_egg","localizedName":"Chicken Spawn Egg"},{"id":"minecraft:chipped_anvil","localizedName":"Air"},{"id":"minecraft:chiseled_quartz_block","localizedName":"Air"},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Air"},{"id":"minecraft:chiseled_sandstone","localizedName":"Air"},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Air"},{"id":"minecraft:chorus_flower","localizedName":"Air"},{"id":"minecraft:chorus_fruit","localizedName":"Chorus Fruit"},{"id":"minecraft:chorus_plant","localizedName":"Air"},{"id":"minecraft:clay","localizedName":"Air"},{"id":"minecraft:clay_ball","localizedName":"Clay"},{"id":"minecraft:clock","localizedName":"Clock"},{"id":"minecraft:coal","localizedName":"Coal"},{"id":"minecraft:coal_block","localizedName":"Air"},{"id":"minecraft:coal_ore","localizedName":"Air"},{"id":"minecraft:coarse_dirt","localizedName":"Air"},{"id":"minecraft:cobblestone","localizedName":"Air"},{"id":"minecraft:cobblestone_slab","localizedName":"Air"},{"id":"minecraft:cobblestone_stairs","localizedName":"Air"},{"id":"minecraft:cobblestone_wall","localizedName":"Air"},{"id":"minecraft:cobweb","localizedName":"Air"},{"id":"minecraft:cocoa_beans","localizedName":"Cocoa Beans"},{"id":"minecraft:cod","localizedName":"Raw Cod"},{"id":"minecraft:cod_bucket","localizedName":"Bucket of Cod"},{"id":"minecraft:cod_spawn_egg","localizedName":"Cod Spawn Egg"},{"id":"minecraft:command_block","localizedName":"Air"},{"id":"minecraft:command_block_minecart","localizedName":"Minecart with Command Block"},{"id":"minecraft:comparator","localizedName":"Air"},{"id":"minecraft:compass","localizedName":"Compass"},{"id":"minecraft:conduit","localizedName":"Air"},{"id":"minecraft:cooked_beef","localizedName":"Steak"},{"id":"minecraft:cooked_chicken","localizedName":"Cooked Chicken"},{"id":"minecraft:cooked_cod","localizedName":"Cooked Cod"},{"id":"minecraft:cooked_mutton","localizedName":"Cooked Mutton"},{"id":"minecraft:cooked_porkchop","localizedName":"Cooked Porkchop"},{"id":"minecraft:cooked_rabbit","localizedName":"Cooked Rabbit"},{"id":"minecraft:cooked_salmon","localizedName":"Cooked Salmon"},{"id":"minecraft:cookie","localizedName":"Cookie"},{"id":"minecraft:cow_spawn_egg","localizedName":"Cow Spawn Egg"},{"id":"minecraft:cracked_stone_bricks","localizedName":"Air"},{"id":"minecraft:crafting_table","localizedName":"Air"},{"id":"minecraft:creeper_head","localizedName":"Air"},{"id":"minecraft:creeper_spawn_egg","localizedName":"Creeper Spawn Egg"},{"id":"minecraft:cut_red_sandstone","localizedName":"Air"},{"id":"minecraft:cut_sandstone","localizedName":"Air"},{"id":"minecraft:cyan_banner","localizedName":"Air"},{"id":"minecraft:cyan_bed","localizedName":"Air"},{"id":"minecraft:cyan_carpet","localizedName":"Air"},{"id":"minecraft:cyan_concrete","localizedName":"Air"},{"id":"minecraft:cyan_concrete_powder","localizedName":"Air"},{"id":"minecraft:cyan_dye","localizedName":"Cyan Dye"},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:cyan_shulker_box","localizedName":"Air"},{"id":"minecraft:cyan_stained_glass","localizedName":"Air"},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:cyan_terracotta","localizedName":"Air"},{"id":"minecraft:cyan_wool","localizedName":"Air"},{"id":"minecraft:damaged_anvil","localizedName":"Air"},{"id":"minecraft:dandelion","localizedName":"Air"},{"id":"minecraft:dandelion_yellow","localizedName":"Dandelion Yellow"},{"id":"minecraft:dark_oak_boat","localizedName":"Dark Oak Boat"},{"id":"minecraft:dark_oak_button","localizedName":"Air"},{"id":"minecraft:dark_oak_door","localizedName":"Air"},{"id":"minecraft:dark_oak_fence","localizedName":"Air"},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Air"},{"id":"minecraft:dark_oak_leaves","localizedName":"Air"},{"id":"minecraft:dark_oak_log","localizedName":"Air"},{"id":"minecraft:dark_oak_planks","localizedName":"Air"},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Air"},{"id":"minecraft:dark_oak_sapling","localizedName":"Air"},{"id":"minecraft:dark_oak_slab","localizedName":"Air"},{"id":"minecraft:dark_oak_stairs","localizedName":"Air"},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Air"},{"id":"minecraft:dark_oak_wood","localizedName":"Air"},{"id":"minecraft:dark_prismarine","localizedName":"Air"},{"id":"minecraft:dark_prismarine_slab","localizedName":"Air"},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Air"},{"id":"minecraft:daylight_detector","localizedName":"Air"},{"id":"minecraft:dead_brain_coral","localizedName":"Air"},{"id":"minecraft:dead_brain_coral_block","localizedName":"Air"},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Air"},{"id":"minecraft:dead_bubble_coral","localizedName":"Air"},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Air"},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Air"},{"id":"minecraft:dead_bush","localizedName":"Air"},{"id":"minecraft:dead_fire_coral","localizedName":"Air"},{"id":"minecraft:dead_fire_coral_block","localizedName":"Air"},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Air"},{"id":"minecraft:dead_horn_coral","localizedName":"Air"},{"id":"minecraft:dead_horn_coral_block","localizedName":"Air"},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Air"},{"id":"minecraft:dead_tube_coral","localizedName":"Air"},{"id":"minecraft:dead_tube_coral_block","localizedName":"Air"},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Air"},{"id":"minecraft:debug_stick","localizedName":"Debug Stick"},{"id":"minecraft:detector_rail","localizedName":"Air"},{"id":"minecraft:diamond","localizedName":"Diamond"},{"id":"minecraft:diamond_axe","localizedName":"Diamond Axe"},{"id":"minecraft:diamond_block","localizedName":"Air"},{"id":"minecraft:diamond_boots","localizedName":"Diamond Boots"},{"id":"minecraft:diamond_chestplate","localizedName":"Diamond Chestplate"},{"id":"minecraft:diamond_helmet","localizedName":"Diamond Helmet"},{"id":"minecraft:diamond_hoe","localizedName":"Diamond Hoe"},{"id":"minecraft:diamond_horse_armor","localizedName":"Diamond Horse Armor"},{"id":"minecraft:diamond_leggings","localizedName":"Diamond Leggings"},{"id":"minecraft:diamond_ore","localizedName":"Air"},{"id":"minecraft:diamond_pickaxe","localizedName":"Diamond Pickaxe"},{"id":"minecraft:diamond_shovel","localizedName":"Diamond Shovel"},{"id":"minecraft:diamond_sword","localizedName":"Diamond Sword"},{"id":"minecraft:diorite","localizedName":"Air"},{"id":"minecraft:dirt","localizedName":"Air"},{"id":"minecraft:dispenser","localizedName":"Air"},{"id":"minecraft:dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg"},{"id":"minecraft:donkey_spawn_egg","localizedName":"Donkey Spawn Egg"},{"id":"minecraft:dragon_breath","localizedName":"Dragon's Breath"},{"id":"minecraft:dragon_egg","localizedName":"Air"},{"id":"minecraft:dragon_head","localizedName":"Air"},{"id":"minecraft:dried_kelp","localizedName":"Dried Kelp"},{"id":"minecraft:dried_kelp_block","localizedName":"Air"},{"id":"minecraft:dropper","localizedName":"Air"},{"id":"minecraft:drowned_spawn_egg","localizedName":"Drowned Spawn Egg"},{"id":"minecraft:egg","localizedName":"Egg"},{"id":"minecraft:elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg"},{"id":"minecraft:elytra","localizedName":"Elytra"},{"id":"minecraft:emerald","localizedName":"Emerald"},{"id":"minecraft:emerald_block","localizedName":"Air"},{"id":"minecraft:emerald_ore","localizedName":"Air"},{"id":"minecraft:enchanted_book","localizedName":"Enchanted Book"},{"id":"minecraft:enchanted_golden_apple","localizedName":"Enchanted Golden Apple"},{"id":"minecraft:enchanting_table","localizedName":"Air"},{"id":"minecraft:end_crystal","localizedName":"End Crystal"},{"id":"minecraft:end_portal_frame","localizedName":"Air"},{"id":"minecraft:end_rod","localizedName":"Air"},{"id":"minecraft:end_stone","localizedName":"Air"},{"id":"minecraft:end_stone_bricks","localizedName":"Air"},{"id":"minecraft:ender_chest","localizedName":"Air"},{"id":"minecraft:ender_eye","localizedName":"Eye of Ender"},{"id":"minecraft:ender_pearl","localizedName":"Ender Pearl"},{"id":"minecraft:enderman_spawn_egg","localizedName":"Enderman Spawn Egg"},{"id":"minecraft:endermite_spawn_egg","localizedName":"Endermite Spawn Egg"},{"id":"minecraft:evoker_spawn_egg","localizedName":"Evoker Spawn Egg"},{"id":"minecraft:experience_bottle","localizedName":"Bottle o' Enchanting"},{"id":"minecraft:farmland","localizedName":"Air"},{"id":"minecraft:feather","localizedName":"Feather"},{"id":"minecraft:fermented_spider_eye","localizedName":"Fermented Spider Eye"},{"id":"minecraft:fern","localizedName":"Air"},{"id":"minecraft:filled_map","localizedName":"Map"},{"id":"minecraft:fire_charge","localizedName":"Fire Charge"},{"id":"minecraft:fire_coral","localizedName":"Air"},{"id":"minecraft:fire_coral_block","localizedName":"Air"},{"id":"minecraft:fire_coral_fan","localizedName":"Air"},{"id":"minecraft:firework_rocket","localizedName":"Firework Rocket"},{"id":"minecraft:firework_star","localizedName":"Firework Star"},{"id":"minecraft:fishing_rod","localizedName":"Fishing Rod"},{"id":"minecraft:flint","localizedName":"Flint"},{"id":"minecraft:flint_and_steel","localizedName":"Flint and Steel"},{"id":"minecraft:flower_pot","localizedName":"Air"},{"id":"minecraft:furnace","localizedName":"Air"},{"id":"minecraft:furnace_minecart","localizedName":"Minecart with Furnace"},{"id":"minecraft:ghast_spawn_egg","localizedName":"Ghast Spawn Egg"},{"id":"minecraft:ghast_tear","localizedName":"Ghast Tear"},{"id":"minecraft:glass","localizedName":"Air"},{"id":"minecraft:glass_bottle","localizedName":"Glass Bottle"},{"id":"minecraft:glass_pane","localizedName":"Air"},{"id":"minecraft:glistering_melon_slice","localizedName":"Glistering Melon Slice"},{"id":"minecraft:glowstone","localizedName":"Air"},{"id":"minecraft:glowstone_dust","localizedName":"Glowstone Dust"},{"id":"minecraft:gold_block","localizedName":"Air"},{"id":"minecraft:gold_ingot","localizedName":"Gold Ingot"},{"id":"minecraft:gold_nugget","localizedName":"Gold Nugget"},{"id":"minecraft:gold_ore","localizedName":"Air"},{"id":"minecraft:golden_apple","localizedName":"Golden Apple"},{"id":"minecraft:golden_axe","localizedName":"Golden Axe"},{"id":"minecraft:golden_boots","localizedName":"Golden Boots"},{"id":"minecraft:golden_carrot","localizedName":"Golden Carrot"},{"id":"minecraft:golden_chestplate","localizedName":"Golden Chestplate"},{"id":"minecraft:golden_helmet","localizedName":"Golden Helmet"},{"id":"minecraft:golden_hoe","localizedName":"Golden Hoe"},{"id":"minecraft:golden_horse_armor","localizedName":"Golden Horse Armor"},{"id":"minecraft:golden_leggings","localizedName":"Golden Leggings"},{"id":"minecraft:golden_pickaxe","localizedName":"Golden Pickaxe"},{"id":"minecraft:golden_shovel","localizedName":"Golden Shovel"},{"id":"minecraft:golden_sword","localizedName":"Golden Sword"},{"id":"minecraft:granite","localizedName":"Air"},{"id":"minecraft:grass","localizedName":"Air"},{"id":"minecraft:grass_block","localizedName":"Air"},{"id":"minecraft:grass_path","localizedName":"Air"},{"id":"minecraft:gravel","localizedName":"Air"},{"id":"minecraft:gray_banner","localizedName":"Air"},{"id":"minecraft:gray_bed","localizedName":"Air"},{"id":"minecraft:gray_carpet","localizedName":"Air"},{"id":"minecraft:gray_concrete","localizedName":"Air"},{"id":"minecraft:gray_concrete_powder","localizedName":"Air"},{"id":"minecraft:gray_dye","localizedName":"Gray Dye"},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:gray_shulker_box","localizedName":"Air"},{"id":"minecraft:gray_stained_glass","localizedName":"Air"},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:gray_terracotta","localizedName":"Air"},{"id":"minecraft:gray_wool","localizedName":"Air"},{"id":"minecraft:green_banner","localizedName":"Air"},{"id":"minecraft:green_bed","localizedName":"Air"},{"id":"minecraft:green_carpet","localizedName":"Air"},{"id":"minecraft:green_concrete","localizedName":"Air"},{"id":"minecraft:green_concrete_powder","localizedName":"Air"},{"id":"minecraft:green_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:green_shulker_box","localizedName":"Air"},{"id":"minecraft:green_stained_glass","localizedName":"Air"},{"id":"minecraft:green_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:green_terracotta","localizedName":"Air"},{"id":"minecraft:green_wool","localizedName":"Air"},{"id":"minecraft:guardian_spawn_egg","localizedName":"Guardian Spawn Egg"},{"id":"minecraft:gunpowder","localizedName":"Gunpowder"},{"id":"minecraft:hay_block","localizedName":"Air"},{"id":"minecraft:heart_of_the_sea","localizedName":"Heart of the Sea"},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Air"},{"id":"minecraft:hopper","localizedName":"Air"},{"id":"minecraft:hopper_minecart","localizedName":"Minecart with Hopper"},{"id":"minecraft:horn_coral","localizedName":"Air"},{"id":"minecraft:horn_coral_block","localizedName":"Air"},{"id":"minecraft:horn_coral_fan","localizedName":"Air"},{"id":"minecraft:horse_spawn_egg","localizedName":"Horse Spawn Egg"},{"id":"minecraft:husk_spawn_egg","localizedName":"Husk Spawn Egg"},{"id":"minecraft:ice","localizedName":"Air"},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Air"},{"id":"minecraft:infested_cobblestone","localizedName":"Air"},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Air"},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Air"},{"id":"minecraft:infested_stone","localizedName":"Air"},{"id":"minecraft:infested_stone_bricks","localizedName":"Air"},{"id":"minecraft:ink_sac","localizedName":"Ink Sac"},{"id":"minecraft:iron_axe","localizedName":"Iron Axe"},{"id":"minecraft:iron_bars","localizedName":"Air"},{"id":"minecraft:iron_block","localizedName":"Air"},{"id":"minecraft:iron_boots","localizedName":"Iron Boots"},{"id":"minecraft:iron_chestplate","localizedName":"Iron Chestplate"},{"id":"minecraft:iron_door","localizedName":"Air"},{"id":"minecraft:iron_helmet","localizedName":"Iron Helmet"},{"id":"minecraft:iron_hoe","localizedName":"Iron Hoe"},{"id":"minecraft:iron_horse_armor","localizedName":"Iron Horse Armor"},{"id":"minecraft:iron_ingot","localizedName":"Iron Ingot"},{"id":"minecraft:iron_leggings","localizedName":"Iron Leggings"},{"id":"minecraft:iron_nugget","localizedName":"Iron Nugget"},{"id":"minecraft:iron_ore","localizedName":"Air"},{"id":"minecraft:iron_pickaxe","localizedName":"Iron Pickaxe"},{"id":"minecraft:iron_shovel","localizedName":"Iron Shovel"},{"id":"minecraft:iron_sword","localizedName":"Iron Sword"},{"id":"minecraft:iron_trapdoor","localizedName":"Air"},{"id":"minecraft:item_frame","localizedName":"Item Frame"},{"id":"minecraft:jack_o_lantern","localizedName":"Air"},{"id":"minecraft:jukebox","localizedName":"Air"},{"id":"minecraft:jungle_boat","localizedName":"Jungle Boat"},{"id":"minecraft:jungle_button","localizedName":"Air"},{"id":"minecraft:jungle_door","localizedName":"Air"},{"id":"minecraft:jungle_fence","localizedName":"Air"},{"id":"minecraft:jungle_fence_gate","localizedName":"Air"},{"id":"minecraft:jungle_leaves","localizedName":"Air"},{"id":"minecraft:jungle_log","localizedName":"Air"},{"id":"minecraft:jungle_planks","localizedName":"Air"},{"id":"minecraft:jungle_pressure_plate","localizedName":"Air"},{"id":"minecraft:jungle_sapling","localizedName":"Air"},{"id":"minecraft:jungle_slab","localizedName":"Air"},{"id":"minecraft:jungle_stairs","localizedName":"Air"},{"id":"minecraft:jungle_trapdoor","localizedName":"Air"},{"id":"minecraft:jungle_wood","localizedName":"Air"},{"id":"minecraft:kelp","localizedName":"Air"},{"id":"minecraft:knowledge_book","localizedName":"Knowledge Book"},{"id":"minecraft:ladder","localizedName":"Air"},{"id":"minecraft:lapis_block","localizedName":"Air"},{"id":"minecraft:lapis_lazuli","localizedName":"Lapis Lazuli"},{"id":"minecraft:lapis_ore","localizedName":"Air"},{"id":"minecraft:large_fern","localizedName":"Air"},{"id":"minecraft:lava_bucket","localizedName":"Lava Bucket"},{"id":"minecraft:lead","localizedName":"Lead"},{"id":"minecraft:leather","localizedName":"Leather"},{"id":"minecraft:leather_boots","localizedName":"Leather Boots"},{"id":"minecraft:leather_chestplate","localizedName":"Leather Tunic"},{"id":"minecraft:leather_helmet","localizedName":"Leather Cap"},{"id":"minecraft:leather_leggings","localizedName":"Leather Pants"},{"id":"minecraft:lever","localizedName":"Air"},{"id":"minecraft:light_blue_banner","localizedName":"Air"},{"id":"minecraft:light_blue_bed","localizedName":"Air"},{"id":"minecraft:light_blue_carpet","localizedName":"Air"},{"id":"minecraft:light_blue_concrete","localizedName":"Air"},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Air"},{"id":"minecraft:light_blue_dye","localizedName":"Light Blue Dye"},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:light_blue_shulker_box","localizedName":"Air"},{"id":"minecraft:light_blue_stained_glass","localizedName":"Air"},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:light_blue_terracotta","localizedName":"Air"},{"id":"minecraft:light_blue_wool","localizedName":"Air"},{"id":"minecraft:light_gray_banner","localizedName":"Air"},{"id":"minecraft:light_gray_bed","localizedName":"Air"},{"id":"minecraft:light_gray_carpet","localizedName":"Air"},{"id":"minecraft:light_gray_concrete","localizedName":"Air"},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Air"},{"id":"minecraft:light_gray_dye","localizedName":"Light Gray Dye"},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:light_gray_shulker_box","localizedName":"Air"},{"id":"minecraft:light_gray_stained_glass","localizedName":"Air"},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:light_gray_terracotta","localizedName":"Air"},{"id":"minecraft:light_gray_wool","localizedName":"Air"},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Air"},{"id":"minecraft:lilac","localizedName":"Air"},{"id":"minecraft:lily_pad","localizedName":"Air"},{"id":"minecraft:lime_banner","localizedName":"Air"},{"id":"minecraft:lime_bed","localizedName":"Air"},{"id":"minecraft:lime_carpet","localizedName":"Air"},{"id":"minecraft:lime_concrete","localizedName":"Air"},{"id":"minecraft:lime_concrete_powder","localizedName":"Air"},{"id":"minecraft:lime_dye","localizedName":"Lime Dye"},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:lime_shulker_box","localizedName":"Air"},{"id":"minecraft:lime_stained_glass","localizedName":"Air"},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:lime_terracotta","localizedName":"Air"},{"id":"minecraft:lime_wool","localizedName":"Air"},{"id":"minecraft:lingering_potion","localizedName":"Lingering Water Bottle"},{"id":"minecraft:llama_spawn_egg","localizedName":"Llama Spawn Egg"},{"id":"minecraft:magenta_banner","localizedName":"Air"},{"id":"minecraft:magenta_bed","localizedName":"Air"},{"id":"minecraft:magenta_carpet","localizedName":"Air"},{"id":"minecraft:magenta_concrete","localizedName":"Air"},{"id":"minecraft:magenta_concrete_powder","localizedName":"Air"},{"id":"minecraft:magenta_dye","localizedName":"Magenta Dye"},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:magenta_shulker_box","localizedName":"Air"},{"id":"minecraft:magenta_stained_glass","localizedName":"Air"},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:magenta_terracotta","localizedName":"Air"},{"id":"minecraft:magenta_wool","localizedName":"Air"},{"id":"minecraft:magma_block","localizedName":"Air"},{"id":"minecraft:magma_cream","localizedName":"Magma Cream"},{"id":"minecraft:magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg"},{"id":"minecraft:map","localizedName":"Empty Map"},{"id":"minecraft:melon","localizedName":"Air"},{"id":"minecraft:melon_seeds","localizedName":"Melon Seeds"},{"id":"minecraft:melon_slice","localizedName":"Melon Slice"},{"id":"minecraft:milk_bucket","localizedName":"Milk Bucket"},{"id":"minecraft:minecart","localizedName":"Minecart"},{"id":"minecraft:mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg"},{"id":"minecraft:mossy_cobblestone","localizedName":"Air"},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Air"},{"id":"minecraft:mossy_stone_bricks","localizedName":"Air"},{"id":"minecraft:mule_spawn_egg","localizedName":"Mule Spawn Egg"},{"id":"minecraft:mushroom_stem","localizedName":"Air"},{"id":"minecraft:mushroom_stew","localizedName":"Mushroom Stew"},{"id":"minecraft:music_disc_11","localizedName":"Music Disc"},{"id":"minecraft:music_disc_13","localizedName":"Music Disc"},{"id":"minecraft:music_disc_blocks","localizedName":"Music Disc"},{"id":"minecraft:music_disc_cat","localizedName":"Music Disc"},{"id":"minecraft:music_disc_chirp","localizedName":"Music Disc"},{"id":"minecraft:music_disc_far","localizedName":"Music Disc"},{"id":"minecraft:music_disc_mall","localizedName":"Music Disc"},{"id":"minecraft:music_disc_mellohi","localizedName":"Music Disc"},{"id":"minecraft:music_disc_stal","localizedName":"Music Disc"},{"id":"minecraft:music_disc_strad","localizedName":"Music Disc"},{"id":"minecraft:music_disc_wait","localizedName":"Music Disc"},{"id":"minecraft:music_disc_ward","localizedName":"Music Disc"},{"id":"minecraft:mutton","localizedName":"Raw Mutton"},{"id":"minecraft:mycelium","localizedName":"Air"},{"id":"minecraft:name_tag","localizedName":"Name Tag"},{"id":"minecraft:nautilus_shell","localizedName":"Nautilus Shell"},{"id":"minecraft:nether_brick","localizedName":"Nether Brick"},{"id":"minecraft:nether_brick_fence","localizedName":"Air"},{"id":"minecraft:nether_brick_slab","localizedName":"Air"},{"id":"minecraft:nether_brick_stairs","localizedName":"Air"},{"id":"minecraft:nether_bricks","localizedName":"Air"},{"id":"minecraft:nether_quartz_ore","localizedName":"Air"},{"id":"minecraft:nether_star","localizedName":"Nether Star"},{"id":"minecraft:nether_wart","localizedName":"Nether Wart"},{"id":"minecraft:nether_wart_block","localizedName":"Air"},{"id":"minecraft:netherrack","localizedName":"Air"},{"id":"minecraft:note_block","localizedName":"Air"},{"id":"minecraft:oak_boat","localizedName":"Oak Boat"},{"id":"minecraft:oak_button","localizedName":"Air"},{"id":"minecraft:oak_door","localizedName":"Air"},{"id":"minecraft:oak_fence","localizedName":"Air"},{"id":"minecraft:oak_fence_gate","localizedName":"Air"},{"id":"minecraft:oak_leaves","localizedName":"Air"},{"id":"minecraft:oak_log","localizedName":"Air"},{"id":"minecraft:oak_planks","localizedName":"Air"},{"id":"minecraft:oak_pressure_plate","localizedName":"Air"},{"id":"minecraft:oak_sapling","localizedName":"Air"},{"id":"minecraft:oak_slab","localizedName":"Air"},{"id":"minecraft:oak_stairs","localizedName":"Air"},{"id":"minecraft:oak_trapdoor","localizedName":"Air"},{"id":"minecraft:oak_wood","localizedName":"Air"},{"id":"minecraft:observer","localizedName":"Air"},{"id":"minecraft:obsidian","localizedName":"Air"},{"id":"minecraft:ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg"},{"id":"minecraft:orange_banner","localizedName":"Air"},{"id":"minecraft:orange_bed","localizedName":"Air"},{"id":"minecraft:orange_carpet","localizedName":"Air"},{"id":"minecraft:orange_concrete","localizedName":"Air"},{"id":"minecraft:orange_concrete_powder","localizedName":"Air"},{"id":"minecraft:orange_dye","localizedName":"Orange Dye"},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:orange_shulker_box","localizedName":"Air"},{"id":"minecraft:orange_stained_glass","localizedName":"Air"},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:orange_terracotta","localizedName":"Air"},{"id":"minecraft:orange_tulip","localizedName":"Air"},{"id":"minecraft:orange_wool","localizedName":"Air"},{"id":"minecraft:oxeye_daisy","localizedName":"Air"},{"id":"minecraft:packed_ice","localizedName":"Air"},{"id":"minecraft:painting","localizedName":"Painting"},{"id":"minecraft:paper","localizedName":"Paper"},{"id":"minecraft:parrot_spawn_egg","localizedName":"Parrot Spawn Egg"},{"id":"minecraft:peony","localizedName":"Air"},{"id":"minecraft:petrified_oak_slab","localizedName":"Air"},{"id":"minecraft:phantom_membrane","localizedName":"Phantom Membrane"},{"id":"minecraft:phantom_spawn_egg","localizedName":"Phantom Spawn Egg"},{"id":"minecraft:pig_spawn_egg","localizedName":"Pig Spawn Egg"},{"id":"minecraft:pink_banner","localizedName":"Air"},{"id":"minecraft:pink_bed","localizedName":"Air"},{"id":"minecraft:pink_carpet","localizedName":"Air"},{"id":"minecraft:pink_concrete","localizedName":"Air"},{"id":"minecraft:pink_concrete_powder","localizedName":"Air"},{"id":"minecraft:pink_dye","localizedName":"Pink Dye"},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:pink_shulker_box","localizedName":"Air"},{"id":"minecraft:pink_stained_glass","localizedName":"Air"},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:pink_terracotta","localizedName":"Air"},{"id":"minecraft:pink_tulip","localizedName":"Air"},{"id":"minecraft:pink_wool","localizedName":"Air"},{"id":"minecraft:piston","localizedName":"Air"},{"id":"minecraft:player_head","localizedName":"Air"},{"id":"minecraft:podzol","localizedName":"Air"},{"id":"minecraft:poisonous_potato","localizedName":"Poisonous Potato"},{"id":"minecraft:polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg"},{"id":"minecraft:polished_andesite","localizedName":"Air"},{"id":"minecraft:polished_diorite","localizedName":"Air"},{"id":"minecraft:polished_granite","localizedName":"Air"},{"id":"minecraft:popped_chorus_fruit","localizedName":"Popped Chorus Fruit"},{"id":"minecraft:poppy","localizedName":"Air"},{"id":"minecraft:porkchop","localizedName":"Raw Porkchop"},{"id":"minecraft:potato","localizedName":"Potato"},{"id":"minecraft:potion","localizedName":"Water Bottle"},{"id":"minecraft:powered_rail","localizedName":"Air"},{"id":"minecraft:prismarine","localizedName":"Air"},{"id":"minecraft:prismarine_brick_slab","localizedName":"Air"},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Air"},{"id":"minecraft:prismarine_bricks","localizedName":"Air"},{"id":"minecraft:prismarine_crystals","localizedName":"Prismarine Crystals"},{"id":"minecraft:prismarine_shard","localizedName":"Prismarine Shard"},{"id":"minecraft:prismarine_slab","localizedName":"Air"},{"id":"minecraft:prismarine_stairs","localizedName":"Air"},{"id":"minecraft:pufferfish","localizedName":"Pufferfish"},{"id":"minecraft:pufferfish_bucket","localizedName":"Bucket of Pufferfish"},{"id":"minecraft:pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg"},{"id":"minecraft:pumpkin","localizedName":"Air"},{"id":"minecraft:pumpkin_pie","localizedName":"Pumpkin Pie"},{"id":"minecraft:pumpkin_seeds","localizedName":"Pumpkin Seeds"},{"id":"minecraft:purple_banner","localizedName":"Air"},{"id":"minecraft:purple_bed","localizedName":"Air"},{"id":"minecraft:purple_carpet","localizedName":"Air"},{"id":"minecraft:purple_concrete","localizedName":"Air"},{"id":"minecraft:purple_concrete_powder","localizedName":"Air"},{"id":"minecraft:purple_dye","localizedName":"Purple Dye"},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:purple_shulker_box","localizedName":"Air"},{"id":"minecraft:purple_stained_glass","localizedName":"Air"},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:purple_terracotta","localizedName":"Air"},{"id":"minecraft:purple_wool","localizedName":"Air"},{"id":"minecraft:purpur_block","localizedName":"Air"},{"id":"minecraft:purpur_pillar","localizedName":"Air"},{"id":"minecraft:purpur_slab","localizedName":"Air"},{"id":"minecraft:purpur_stairs","localizedName":"Air"},{"id":"minecraft:quartz","localizedName":"Nether Quartz"},{"id":"minecraft:quartz_block","localizedName":"Air"},{"id":"minecraft:quartz_pillar","localizedName":"Air"},{"id":"minecraft:quartz_slab","localizedName":"Air"},{"id":"minecraft:quartz_stairs","localizedName":"Air"},{"id":"minecraft:rabbit","localizedName":"Raw Rabbit"},{"id":"minecraft:rabbit_foot","localizedName":"Rabbit's Foot"},{"id":"minecraft:rabbit_hide","localizedName":"Rabbit Hide"},{"id":"minecraft:rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg"},{"id":"minecraft:rabbit_stew","localizedName":"Rabbit Stew"},{"id":"minecraft:rail","localizedName":"Air"},{"id":"minecraft:red_banner","localizedName":"Air"},{"id":"minecraft:red_bed","localizedName":"Air"},{"id":"minecraft:red_carpet","localizedName":"Air"},{"id":"minecraft:red_concrete","localizedName":"Air"},{"id":"minecraft:red_concrete_powder","localizedName":"Air"},{"id":"minecraft:red_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:red_mushroom","localizedName":"Air"},{"id":"minecraft:red_mushroom_block","localizedName":"Air"},{"id":"minecraft:red_nether_bricks","localizedName":"Air"},{"id":"minecraft:red_sand","localizedName":"Air"},{"id":"minecraft:red_sandstone","localizedName":"Air"},{"id":"minecraft:red_sandstone_slab","localizedName":"Air"},{"id":"minecraft:red_sandstone_stairs","localizedName":"Air"},{"id":"minecraft:red_shulker_box","localizedName":"Air"},{"id":"minecraft:red_stained_glass","localizedName":"Air"},{"id":"minecraft:red_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:red_terracotta","localizedName":"Air"},{"id":"minecraft:red_tulip","localizedName":"Air"},{"id":"minecraft:red_wool","localizedName":"Air"},{"id":"minecraft:redstone","localizedName":"Air"},{"id":"minecraft:redstone_block","localizedName":"Air"},{"id":"minecraft:redstone_lamp","localizedName":"Air"},{"id":"minecraft:redstone_ore","localizedName":"Air"},{"id":"minecraft:redstone_torch","localizedName":"Air"},{"id":"minecraft:repeater","localizedName":"Air"},{"id":"minecraft:repeating_command_block","localizedName":"Air"},{"id":"minecraft:rose_bush","localizedName":"Air"},{"id":"minecraft:rose_red","localizedName":"Rose Red"},{"id":"minecraft:rotten_flesh","localizedName":"Rotten Flesh"},{"id":"minecraft:saddle","localizedName":"Saddle"},{"id":"minecraft:salmon","localizedName":"Raw Salmon"},{"id":"minecraft:salmon_bucket","localizedName":"Bucket of Salmon"},{"id":"minecraft:salmon_spawn_egg","localizedName":"Salmon Spawn Egg"},{"id":"minecraft:sand","localizedName":"Air"},{"id":"minecraft:sandstone","localizedName":"Air"},{"id":"minecraft:sandstone_slab","localizedName":"Air"},{"id":"minecraft:sandstone_stairs","localizedName":"Air"},{"id":"minecraft:scute","localizedName":"Scute"},{"id":"minecraft:sea_lantern","localizedName":"Air"},{"id":"minecraft:sea_pickle","localizedName":"Air"},{"id":"minecraft:seagrass","localizedName":"Air"},{"id":"minecraft:shears","localizedName":"Shears"},{"id":"minecraft:sheep_spawn_egg","localizedName":"Sheep Spawn Egg"},{"id":"minecraft:shield","localizedName":"Shield"},{"id":"minecraft:shulker_box","localizedName":"Air"},{"id":"minecraft:shulker_shell","localizedName":"Shulker Shell"},{"id":"minecraft:shulker_spawn_egg","localizedName":"Shulker Spawn Egg"},{"id":"minecraft:sign","localizedName":"Air"},{"id":"minecraft:silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg"},{"id":"minecraft:skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg"},{"id":"minecraft:skeleton_skull","localizedName":"Air"},{"id":"minecraft:skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg"},{"id":"minecraft:slime_ball","localizedName":"Slimeball"},{"id":"minecraft:slime_block","localizedName":"Air"},{"id":"minecraft:slime_spawn_egg","localizedName":"Slime Spawn Egg"},{"id":"minecraft:smooth_quartz","localizedName":"Air"},{"id":"minecraft:smooth_red_sandstone","localizedName":"Air"},{"id":"minecraft:smooth_sandstone","localizedName":"Air"},{"id":"minecraft:smooth_stone","localizedName":"Air"},{"id":"minecraft:snow","localizedName":"Air"},{"id":"minecraft:snow_block","localizedName":"Air"},{"id":"minecraft:snowball","localizedName":"Snowball"},{"id":"minecraft:soul_sand","localizedName":"Air"},{"id":"minecraft:spawner","localizedName":"Air"},{"id":"minecraft:spectral_arrow","localizedName":"Spectral Arrow"},{"id":"minecraft:spider_eye","localizedName":"Spider Eye"},{"id":"minecraft:spider_spawn_egg","localizedName":"Spider Spawn Egg"},{"id":"minecraft:splash_potion","localizedName":"Splash Water Bottle"},{"id":"minecraft:sponge","localizedName":"Air"},{"id":"minecraft:spruce_boat","localizedName":"Spruce Boat"},{"id":"minecraft:spruce_button","localizedName":"Air"},{"id":"minecraft:spruce_door","localizedName":"Air"},{"id":"minecraft:spruce_fence","localizedName":"Air"},{"id":"minecraft:spruce_fence_gate","localizedName":"Air"},{"id":"minecraft:spruce_leaves","localizedName":"Air"},{"id":"minecraft:spruce_log","localizedName":"Air"},{"id":"minecraft:spruce_planks","localizedName":"Air"},{"id":"minecraft:spruce_pressure_plate","localizedName":"Air"},{"id":"minecraft:spruce_sapling","localizedName":"Air"},{"id":"minecraft:spruce_slab","localizedName":"Air"},{"id":"minecraft:spruce_stairs","localizedName":"Air"},{"id":"minecraft:spruce_trapdoor","localizedName":"Air"},{"id":"minecraft:spruce_wood","localizedName":"Air"},{"id":"minecraft:squid_spawn_egg","localizedName":"Squid Spawn Egg"},{"id":"minecraft:stick","localizedName":"Stick"},{"id":"minecraft:sticky_piston","localizedName":"Air"},{"id":"minecraft:stone","localizedName":"Air"},{"id":"minecraft:stone_axe","localizedName":"Stone Axe"},{"id":"minecraft:stone_brick_slab","localizedName":"Air"},{"id":"minecraft:stone_brick_stairs","localizedName":"Air"},{"id":"minecraft:stone_bricks","localizedName":"Air"},{"id":"minecraft:stone_button","localizedName":"Air"},{"id":"minecraft:stone_hoe","localizedName":"Stone Hoe"},{"id":"minecraft:stone_pickaxe","localizedName":"Stone Pickaxe"},{"id":"minecraft:stone_pressure_plate","localizedName":"Air"},{"id":"minecraft:stone_shovel","localizedName":"Stone Shovel"},{"id":"minecraft:stone_slab","localizedName":"Air"},{"id":"minecraft:stone_sword","localizedName":"Stone Sword"},{"id":"minecraft:stray_spawn_egg","localizedName":"Stray Spawn Egg"},{"id":"minecraft:string","localizedName":"String"},{"id":"minecraft:stripped_acacia_log","localizedName":"Air"},{"id":"minecraft:stripped_acacia_wood","localizedName":"Air"},{"id":"minecraft:stripped_birch_log","localizedName":"Air"},{"id":"minecraft:stripped_birch_wood","localizedName":"Air"},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Air"},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Air"},{"id":"minecraft:stripped_jungle_log","localizedName":"Air"},{"id":"minecraft:stripped_jungle_wood","localizedName":"Air"},{"id":"minecraft:stripped_oak_log","localizedName":"Air"},{"id":"minecraft:stripped_oak_wood","localizedName":"Air"},{"id":"minecraft:stripped_spruce_log","localizedName":"Air"},{"id":"minecraft:stripped_spruce_wood","localizedName":"Air"},{"id":"minecraft:structure_block","localizedName":"Air"},{"id":"minecraft:structure_void","localizedName":"Air"},{"id":"minecraft:sugar","localizedName":"Sugar"},{"id":"minecraft:sugar_cane","localizedName":"Air"},{"id":"minecraft:sunflower","localizedName":"Air"},{"id":"minecraft:tall_grass","localizedName":"Air"},{"id":"minecraft:terracotta","localizedName":"Air"},{"id":"minecraft:tipped_arrow","localizedName":"Arrow of Poison"},{"id":"minecraft:tnt","localizedName":"Air"},{"id":"minecraft:tnt_minecart","localizedName":"Minecart with TNT"},{"id":"minecraft:torch","localizedName":"Air"},{"id":"minecraft:totem_of_undying","localizedName":"Totem of Undying"},{"id":"minecraft:trapped_chest","localizedName":"Air"},{"id":"minecraft:trident","localizedName":"Trident"},{"id":"minecraft:tripwire_hook","localizedName":"Air"},{"id":"minecraft:tropical_fish","localizedName":"Tropical Fish"},{"id":"minecraft:tropical_fish_bucket","localizedName":"Bucket of Tropical Fish"},{"id":"minecraft:tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg"},{"id":"minecraft:tube_coral","localizedName":"Air"},{"id":"minecraft:tube_coral_block","localizedName":"Air"},{"id":"minecraft:tube_coral_fan","localizedName":"Air"},{"id":"minecraft:turtle_egg","localizedName":"Air"},{"id":"minecraft:turtle_helmet","localizedName":"Turtle Shell"},{"id":"minecraft:turtle_spawn_egg","localizedName":"Turtle Spawn Egg"},{"id":"minecraft:vex_spawn_egg","localizedName":"Vex Spawn Egg"},{"id":"minecraft:villager_spawn_egg","localizedName":"Villager Spawn Egg"},{"id":"minecraft:vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg"},{"id":"minecraft:vine","localizedName":"Air"},{"id":"minecraft:water_bucket","localizedName":"Water Bucket"},{"id":"minecraft:wet_sponge","localizedName":"Air"},{"id":"minecraft:wheat","localizedName":"Wheat"},{"id":"minecraft:wheat_seeds","localizedName":"Wheat Seeds"},{"id":"minecraft:white_banner","localizedName":"Air"},{"id":"minecraft:white_bed","localizedName":"Air"},{"id":"minecraft:white_carpet","localizedName":"Air"},{"id":"minecraft:white_concrete","localizedName":"Air"},{"id":"minecraft:white_concrete_powder","localizedName":"Air"},{"id":"minecraft:white_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:white_shulker_box","localizedName":"Air"},{"id":"minecraft:white_stained_glass","localizedName":"Air"},{"id":"minecraft:white_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:white_terracotta","localizedName":"Air"},{"id":"minecraft:white_tulip","localizedName":"Air"},{"id":"minecraft:white_wool","localizedName":"Air"},{"id":"minecraft:witch_spawn_egg","localizedName":"Witch Spawn Egg"},{"id":"minecraft:wither_skeleton_skull","localizedName":"Air"},{"id":"minecraft:wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg"},{"id":"minecraft:wolf_spawn_egg","localizedName":"Wolf Spawn Egg"},{"id":"minecraft:wooden_axe","localizedName":"Wooden Axe"},{"id":"minecraft:wooden_hoe","localizedName":"Wooden Hoe"},{"id":"minecraft:wooden_pickaxe","localizedName":"Wooden Pickaxe"},{"id":"minecraft:wooden_shovel","localizedName":"Wooden Shovel"},{"id":"minecraft:wooden_sword","localizedName":"Wooden Sword"},{"id":"minecraft:writable_book","localizedName":"Book and Quill"},{"id":"minecraft:written_book","localizedName":"Written Book"},{"id":"minecraft:yellow_banner","localizedName":"Air"},{"id":"minecraft:yellow_bed","localizedName":"Air"},{"id":"minecraft:yellow_carpet","localizedName":"Air"},{"id":"minecraft:yellow_concrete","localizedName":"Air"},{"id":"minecraft:yellow_concrete_powder","localizedName":"Air"},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Air"},{"id":"minecraft:yellow_shulker_box","localizedName":"Air"},{"id":"minecraft:yellow_stained_glass","localizedName":"Air"},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Air"},{"id":"minecraft:yellow_terracotta","localizedName":"Air"},{"id":"minecraft:yellow_wool","localizedName":"Air"},{"id":"minecraft:zombie_head","localizedName":"Air"},{"id":"minecraft:zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg"},{"id":"minecraft:zombie_pigman_spawn_egg","localizedName":"Zombie Pigman Spawn Egg"},{"id":"minecraft:zombie_spawn_egg","localizedName":"Zombie Spawn Egg"},{"id":"minecraft:zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg"}] \ No newline at end of file diff --git a/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json b/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json new file mode 100644 index 0000000..82c2bdd --- /dev/null +++ b/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json @@ -0,0 +1 @@ +{"blocks":{"0:0":"minecraft:air","1:0":"minecraft:stone","1:1":"minecraft:granite","1:2":"minecraft:polished_granite","1:3":"minecraft:diorite","1:4":"minecraft:polished_diorite","1:5":"minecraft:andesite","1:6":"minecraft:polished_andesite","2:0":"minecraft:grass_block[snowy=false]","3:0":"minecraft:dirt","3:1":"minecraft:coarse_dirt","3:2":"minecraft:podzol[snowy=false]","4:0":"minecraft:cobblestone","5:0":"minecraft:oak_planks","5:1":"minecraft:spruce_planks","5:2":"minecraft:birch_planks","5:3":"minecraft:jungle_planks","5:4":"minecraft:acacia_planks","5:5":"minecraft:dark_oak_planks","6:0":"minecraft:oak_sapling[stage=0]","6:1":"minecraft:spruce_sapling[stage=0]","6:2":"minecraft:birch_sapling[stage=0]","6:3":"minecraft:jungle_sapling[stage=0]","6:4":"minecraft:acacia_sapling[stage=0]","6:5":"minecraft:dark_oak_sapling[stage=0]","6:8":"minecraft:oak_sapling[stage=1]","6:9":"minecraft:spruce_sapling[stage=1]","6:10":"minecraft:birch_sapling[stage=1]","6:11":"minecraft:jungle_sapling[stage=1]","6:12":"minecraft:acacia_sapling[stage=1]","6:13":"minecraft:dark_oak_sapling[stage=1]","7:0":"minecraft:bedrock","8:0":"minecraft:water[level=0]","8:1":"minecraft:water[level=1]","8:2":"minecraft:water[level=2]","8:3":"minecraft:water[level=3]","8:4":"minecraft:water[level=4]","8:5":"minecraft:water[level=5]","8:6":"minecraft:water[level=6]","8:7":"minecraft:water[level=7]","8:8":"minecraft:water[level=8]","8:9":"minecraft:water[level=9]","8:10":"minecraft:water[level=10]","8:11":"minecraft:water[level=11]","8:12":"minecraft:water[level=12]","8:13":"minecraft:water[level=13]","8:14":"minecraft:water[level=14]","8:15":"minecraft:water[level=15]","9:0":"minecraft:water[level=0]","9:1":"minecraft:water[level=1]","9:2":"minecraft:water[level=2]","9:3":"minecraft:water[level=3]","9:4":"minecraft:water[level=4]","9:5":"minecraft:water[level=5]","9:6":"minecraft:water[level=6]","9:7":"minecraft:water[level=7]","9:8":"minecraft:water[level=8]","9:9":"minecraft:water[level=9]","9:10":"minecraft:water[level=10]","9:11":"minecraft:water[level=11]","9:12":"minecraft:water[level=12]","9:13":"minecraft:water[level=13]","9:14":"minecraft:water[level=14]","9:15":"minecraft:water[level=15]","10:0":"minecraft:lava[level=0]","10:1":"minecraft:lava[level=1]","10:2":"minecraft:lava[level=2]","10:3":"minecraft:lava[level=3]","10:4":"minecraft:lava[level=4]","10:5":"minecraft:lava[level=5]","10:6":"minecraft:lava[level=6]","10:7":"minecraft:lava[level=7]","10:8":"minecraft:lava[level=8]","10:9":"minecraft:lava[level=9]","10:10":"minecraft:lava[level=10]","10:11":"minecraft:lava[level=11]","10:12":"minecraft:lava[level=12]","10:13":"minecraft:lava[level=13]","10:14":"minecraft:lava[level=14]","10:15":"minecraft:lava[level=15]","11:0":"minecraft:lava[level=0]","11:1":"minecraft:lava[level=1]","11:2":"minecraft:lava[level=2]","11:3":"minecraft:lava[level=3]","11:4":"minecraft:lava[level=4]","11:5":"minecraft:lava[level=5]","11:6":"minecraft:lava[level=6]","11:7":"minecraft:lava[level=7]","11:8":"minecraft:lava[level=8]","11:9":"minecraft:lava[level=9]","11:10":"minecraft:lava[level=10]","11:11":"minecraft:lava[level=11]","11:12":"minecraft:lava[level=12]","11:13":"minecraft:lava[level=13]","11:14":"minecraft:lava[level=14]","11:15":"minecraft:lava[level=15]","12:0":"minecraft:sand","12:1":"minecraft:red_sand","13:0":"minecraft:gravel","14:0":"minecraft:gold_ore","15:0":"minecraft:iron_ore","16:0":"minecraft:coal_ore","17:0":"minecraft:oak_log[axis=y]","17:1":"minecraft:spruce_log[axis=y]","17:2":"minecraft:birch_log[axis=y]","17:3":"minecraft:jungle_log[axis=y]","17:4":"minecraft:oak_log[axis=x]","17:5":"minecraft:spruce_log[axis=x]","17:6":"minecraft:birch_log[axis=x]","17:7":"minecraft:jungle_log[axis=x]","17:8":"minecraft:oak_log[axis=z]","17:9":"minecraft:spruce_log[axis=z]","17:10":"minecraft:birch_log[axis=z]","17:11":"minecraft:jungle_log[axis=z]","17:12":"minecraft:oak_wood","17:13":"minecraft:spruce_wood","17:14":"minecraft:birch_wood","17:15":"minecraft:jungle_wood","18:0":"minecraft:oak_leaves[persistent=false,distance=1]","18:1":"minecraft:spruce_leaves[persistent=false,distance=1]","18:2":"minecraft:birch_leaves[persistent=false,distance=1]","18:3":"minecraft:jungle_leaves[persistent=false,distance=1]","18:4":"minecraft:oak_leaves[persistent=true,distance=1]","18:5":"minecraft:spruce_leaves[persistent=true,distance=1]","18:6":"minecraft:birch_leaves[persistent=true,distance=1]","18:7":"minecraft:jungle_leaves[persistent=true,distance=1]","18:8":"minecraft:oak_leaves[persistent=false,distance=1]","18:9":"minecraft:spruce_leaves[persistent=false,distance=1]","18:10":"minecraft:birch_leaves[persistent=false,distance=1]","18:11":"minecraft:jungle_leaves[persistent=false,distance=1]","18:12":"minecraft:oak_leaves[persistent=true,distance=1]","18:13":"minecraft:spruce_leaves[persistent=true,distance=1]","18:14":"minecraft:birch_leaves[persistent=true,distance=1]","18:15":"minecraft:jungle_leaves[persistent=true,distance=1]","19:0":"minecraft:sponge","19:1":"minecraft:wet_sponge","20:0":"minecraft:glass","21:0":"minecraft:lapis_ore","22:0":"minecraft:lapis_block","23:0":"minecraft:dispenser[triggered=false,facing=down]","23:1":"minecraft:dispenser[triggered=false,facing=up]","23:2":"minecraft:dispenser[triggered=false,facing=north]","23:3":"minecraft:dispenser[triggered=false,facing=south]","23:4":"minecraft:dispenser[triggered=false,facing=west]","23:5":"minecraft:dispenser[triggered=false,facing=east]","23:8":"minecraft:dispenser[triggered=true,facing=down]","23:9":"minecraft:dispenser[triggered=true,facing=up]","23:10":"minecraft:dispenser[triggered=true,facing=north]","23:11":"minecraft:dispenser[triggered=true,facing=south]","23:12":"minecraft:dispenser[triggered=true,facing=west]","23:13":"minecraft:dispenser[triggered=true,facing=east]","24:0":"minecraft:sandstone","24:1":"minecraft:chiseled_sandstone","24:2":"minecraft:cut_sandstone","25:0":"minecraft:note_block","26:0":"minecraft:red_bed[part=foot,facing=south,occupied=false]","26:1":"minecraft:red_bed[part=foot,facing=west,occupied=false]","26:2":"minecraft:red_bed[part=foot,facing=north,occupied=false]","26:3":"minecraft:red_bed[part=foot,facing=east,occupied=false]","26:4":"minecraft:red_bed[part=foot,facing=south,occupied=true]","26:5":"minecraft:red_bed[part=foot,facing=west,occupied=true]","26:6":"minecraft:red_bed[part=foot,facing=north,occupied=true]","26:7":"minecraft:red_bed[part=foot,facing=east,occupied=true]","26:8":"minecraft:red_bed[part=head,facing=south,occupied=false]","26:9":"minecraft:red_bed[part=head,facing=west,occupied=false]","26:10":"minecraft:red_bed[part=head,facing=north,occupied=false]","26:11":"minecraft:red_bed[part=head,facing=east,occupied=false]","26:12":"minecraft:red_bed[part=head,facing=south,occupied=true]","26:13":"minecraft:red_bed[part=head,facing=west,occupied=true]","26:14":"minecraft:red_bed[part=head,facing=north,occupied=true]","26:15":"minecraft:red_bed[part=head,facing=east,occupied=true]","27:0":"minecraft:powered_rail[shape=north_south,powered=false]","27:1":"minecraft:powered_rail[shape=east_west,powered=false]","27:2":"minecraft:powered_rail[shape=ascending_east,powered=false]","27:3":"minecraft:powered_rail[shape=ascending_west,powered=false]","27:4":"minecraft:powered_rail[shape=ascending_north,powered=false]","27:5":"minecraft:powered_rail[shape=ascending_south,powered=false]","27:8":"minecraft:powered_rail[shape=north_south,powered=true]","27:9":"minecraft:powered_rail[shape=east_west,powered=true]","27:10":"minecraft:powered_rail[shape=ascending_east,powered=true]","27:11":"minecraft:powered_rail[shape=ascending_west,powered=true]","27:12":"minecraft:powered_rail[shape=ascending_north,powered=true]","27:13":"minecraft:powered_rail[shape=ascending_south,powered=true]","28:0":"minecraft:detector_rail[shape=north_south,powered=false]","28:1":"minecraft:detector_rail[shape=east_west,powered=false]","28:2":"minecraft:detector_rail[shape=ascending_east,powered=false]","28:3":"minecraft:detector_rail[shape=ascending_west,powered=false]","28:4":"minecraft:detector_rail[shape=ascending_north,powered=false]","28:5":"minecraft:detector_rail[shape=ascending_south,powered=false]","28:8":"minecraft:detector_rail[shape=north_south,powered=true]","28:9":"minecraft:detector_rail[shape=east_west,powered=true]","28:10":"minecraft:detector_rail[shape=ascending_east,powered=true]","28:11":"minecraft:detector_rail[shape=ascending_west,powered=true]","28:12":"minecraft:detector_rail[shape=ascending_north,powered=true]","28:13":"minecraft:detector_rail[shape=ascending_south,powered=true]","29:0":"minecraft:sticky_piston[facing=down,extended=false]","29:1":"minecraft:sticky_piston[facing=up,extended=false]","29:2":"minecraft:sticky_piston[facing=north,extended=false]","29:3":"minecraft:sticky_piston[facing=south,extended=false]","29:4":"minecraft:sticky_piston[facing=west,extended=false]","29:5":"minecraft:sticky_piston[facing=east,extended=false]","29:8":"minecraft:sticky_piston[facing=down,extended=true]","29:9":"minecraft:sticky_piston[facing=up,extended=true]","29:10":"minecraft:sticky_piston[facing=north,extended=true]","29:11":"minecraft:sticky_piston[facing=south,extended=true]","29:12":"minecraft:sticky_piston[facing=west,extended=true]","29:13":"minecraft:sticky_piston[facing=east,extended=true]","30:0":"minecraft:cobweb","31:0":"minecraft:dead_bush","31:1":"minecraft:grass","31:2":"minecraft:fern","32:0":"minecraft:dead_bush","33:0":"minecraft:piston[facing=down,extended=false]","33:1":"minecraft:piston[facing=up,extended=false]","33:2":"minecraft:piston[facing=north,extended=false]","33:3":"minecraft:piston[facing=south,extended=false]","33:4":"minecraft:piston[facing=west,extended=false]","33:5":"minecraft:piston[facing=east,extended=false]","33:8":"minecraft:piston[facing=down,extended=true]","33:9":"minecraft:piston[facing=up,extended=true]","33:10":"minecraft:piston[facing=north,extended=true]","33:11":"minecraft:piston[facing=south,extended=true]","33:12":"minecraft:piston[facing=west,extended=true]","33:13":"minecraft:piston[facing=east,extended=true]","34:0":"minecraft:piston_head[short=false,facing=down,type=normal]","34:1":"minecraft:piston_head[short=false,facing=up,type=normal]","34:2":"minecraft:piston_head[short=false,facing=north,type=normal]","34:3":"minecraft:piston_head[short=false,facing=south,type=normal]","34:4":"minecraft:piston_head[short=false,facing=west,type=normal]","34:5":"minecraft:piston_head[short=false,facing=east,type=normal]","34:8":"minecraft:piston_head[short=false,facing=down,type=sticky]","34:9":"minecraft:piston_head[short=false,facing=up,type=sticky]","34:10":"minecraft:piston_head[short=false,facing=north,type=sticky]","34:11":"minecraft:piston_head[short=false,facing=south,type=sticky]","34:12":"minecraft:piston_head[short=false,facing=west,type=sticky]","34:13":"minecraft:piston_head[short=false,facing=east,type=sticky]","35:0":"minecraft:white_wool","35:1":"minecraft:orange_wool","35:2":"minecraft:magenta_wool","35:3":"minecraft:light_blue_wool","35:4":"minecraft:yellow_wool","35:5":"minecraft:lime_wool","35:6":"minecraft:pink_wool","35:7":"minecraft:gray_wool","35:8":"minecraft:light_gray_wool","35:9":"minecraft:cyan_wool","35:10":"minecraft:purple_wool","35:11":"minecraft:blue_wool","35:12":"minecraft:brown_wool","35:13":"minecraft:green_wool","35:14":"minecraft:red_wool","35:15":"minecraft:black_wool","36:0":"minecraft:moving_piston[facing=down,type=normal]","36:1":"minecraft:moving_piston[facing=up,type=normal]","36:2":"minecraft:moving_piston[facing=north,type=normal]","36:3":"minecraft:moving_piston[facing=south,type=normal]","36:4":"minecraft:moving_piston[facing=west,type=normal]","36:5":"minecraft:moving_piston[facing=east,type=normal]","36:8":"minecraft:moving_piston[facing=down,type=sticky]","36:9":"minecraft:moving_piston[facing=up,type=sticky]","36:10":"minecraft:moving_piston[facing=north,type=sticky]","36:11":"minecraft:moving_piston[facing=south,type=sticky]","36:12":"minecraft:moving_piston[facing=west,type=sticky]","36:13":"minecraft:moving_piston[facing=east,type=sticky]","37:0":"minecraft:dandelion","38:0":"minecraft:poppy","38:1":"minecraft:blue_orchid","38:2":"minecraft:allium","38:3":"minecraft:azure_bluet","38:4":"minecraft:red_tulip","38:5":"minecraft:orange_tulip","38:6":"minecraft:white_tulip","38:7":"minecraft:pink_tulip","38:8":"minecraft:oxeye_daisy","39:0":"minecraft:brown_mushroom","40:0":"minecraft:red_mushroom","41:0":"minecraft:gold_block","42:0":"minecraft:iron_block","43:0":"minecraft:stone_slab[type=double]","43:1":"minecraft:sandstone_slab[type=double]","43:2":"minecraft:petrified_oak_slab[type=double]","43:3":"minecraft:cobblestone_slab[type=double]","43:4":"minecraft:brick_slab[type=double]","43:5":"minecraft:stone_brick_slab[type=double]","43:6":"minecraft:nether_brick_slab[type=double]","43:7":"minecraft:quartz_slab[type=double]","43:8":"minecraft:smooth_stone","43:9":"minecraft:smooth_sandstone","43:10":"minecraft:petrified_oak_slab[type=double]","43:11":"minecraft:cobblestone_slab[type=double]","43:12":"minecraft:brick_slab[type=double]","43:13":"minecraft:stone_brick_slab[type=double]","43:14":"minecraft:nether_brick_slab[type=double]","43:15":"minecraft:smooth_quartz","44:0":"minecraft:stone_slab[type=bottom]","44:1":"minecraft:sandstone_slab[type=bottom]","44:2":"minecraft:petrified_oak_slab[type=bottom]","44:3":"minecraft:cobblestone_slab[type=bottom]","44:4":"minecraft:brick_slab[type=bottom]","44:5":"minecraft:stone_brick_slab[type=bottom]","44:6":"minecraft:nether_brick_slab[type=bottom]","44:7":"minecraft:quartz_slab[type=bottom]","44:8":"minecraft:stone_slab[type=top]","44:9":"minecraft:sandstone_slab[type=top]","44:10":"minecraft:petrified_oak_slab[type=top]","44:11":"minecraft:cobblestone_slab[type=top]","44:12":"minecraft:brick_slab[type=top]","44:13":"minecraft:stone_brick_slab[type=top]","44:14":"minecraft:nether_brick_slab[type=top]","44:15":"minecraft:quartz_slab[type=top]","45:0":"minecraft:bricks","46:0":"minecraft:tnt[unstable=false]","46:1":"minecraft:tnt[unstable=true]","47:0":"minecraft:bookshelf","48:0":"minecraft:mossy_cobblestone","49:0":"minecraft:obsidian","50:1":"minecraft:wall_torch[facing=east]","50:2":"minecraft:wall_torch[facing=west]","50:3":"minecraft:wall_torch[facing=south]","50:4":"minecraft:wall_torch[facing=north]","50:5":"minecraft:torch","51:0":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=0]","51:1":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=1]","51:2":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=2]","51:3":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=3]","51:4":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=4]","51:5":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=5]","51:6":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=6]","51:7":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=7]","51:8":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=8]","51:9":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=9]","51:10":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=10]","51:11":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=11]","51:12":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=12]","51:13":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=13]","51:14":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=14]","51:15":"minecraft:fire[east=false,south=false,north=false,west=false,up=false,age=15]","52:0":"minecraft:spawner","53:0":"minecraft:oak_stairs[half=bottom,shape=straight,facing=east]","53:1":"minecraft:oak_stairs[half=bottom,shape=straight,facing=west]","53:2":"minecraft:oak_stairs[half=bottom,shape=straight,facing=south]","53:3":"minecraft:oak_stairs[half=bottom,shape=straight,facing=north]","53:4":"minecraft:oak_stairs[half=top,shape=straight,facing=east]","53:5":"minecraft:oak_stairs[half=top,shape=straight,facing=west]","53:6":"minecraft:oak_stairs[half=top,shape=straight,facing=south]","53:7":"minecraft:oak_stairs[half=top,shape=straight,facing=north]","54:2":"minecraft:chest[facing=north,type=single]","54:3":"minecraft:chest[facing=south,type=single]","54:4":"minecraft:chest[facing=west,type=single]","54:5":"minecraft:chest[facing=east,type=single]","55:0":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=0]","55:1":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=1]","55:2":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=2]","55:3":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=3]","55:4":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=4]","55:5":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=5]","55:6":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=6]","55:7":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=7]","55:8":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=8]","55:9":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=9]","55:10":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=10]","55:11":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=11]","55:12":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=12]","55:13":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=13]","55:14":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=14]","55:15":"minecraft:redstone_wire[east=none,south=none,north=none,west=none,power=15]","56:0":"minecraft:diamond_ore","57:0":"minecraft:diamond_block","58:0":"minecraft:crafting_table","59:0":"minecraft:wheat[age=0]","59:1":"minecraft:wheat[age=1]","59:2":"minecraft:wheat[age=2]","59:3":"minecraft:wheat[age=3]","59:4":"minecraft:wheat[age=4]","59:5":"minecraft:wheat[age=5]","59:6":"minecraft:wheat[age=6]","59:7":"minecraft:wheat[age=7]","60:0":"minecraft:farmland[moisture=0]","60:1":"minecraft:farmland[moisture=1]","60:2":"minecraft:farmland[moisture=2]","60:3":"minecraft:farmland[moisture=3]","60:4":"minecraft:farmland[moisture=4]","60:5":"minecraft:farmland[moisture=5]","60:6":"minecraft:farmland[moisture=6]","60:7":"minecraft:farmland[moisture=7]","61:2":"minecraft:furnace[facing=north,lit=false]","61:3":"minecraft:furnace[facing=south,lit=false]","61:4":"minecraft:furnace[facing=west,lit=false]","61:5":"minecraft:furnace[facing=east,lit=false]","62:2":"minecraft:furnace[facing=north,lit=true]","62:3":"minecraft:furnace[facing=south,lit=true]","62:4":"minecraft:furnace[facing=west,lit=true]","62:5":"minecraft:furnace[facing=east,lit=true]","63:0":"minecraft:sign[rotation=0]","63:1":"minecraft:sign[rotation=1]","63:2":"minecraft:sign[rotation=2]","63:3":"minecraft:sign[rotation=3]","63:4":"minecraft:sign[rotation=4]","63:5":"minecraft:sign[rotation=5]","63:6":"minecraft:sign[rotation=6]","63:7":"minecraft:sign[rotation=7]","63:8":"minecraft:sign[rotation=8]","63:9":"minecraft:sign[rotation=9]","63:10":"minecraft:sign[rotation=10]","63:11":"minecraft:sign[rotation=11]","63:12":"minecraft:sign[rotation=12]","63:13":"minecraft:sign[rotation=13]","63:14":"minecraft:sign[rotation=14]","63:15":"minecraft:sign[rotation=15]","64:0":"minecraft:oak_door[hinge=right,half=lower,powered=false,facing=east,open=false]","64:1":"minecraft:oak_door[hinge=right,half=lower,powered=false,facing=south,open=false]","64:2":"minecraft:oak_door[hinge=right,half=lower,powered=false,facing=west,open=false]","64:3":"minecraft:oak_door[hinge=right,half=lower,powered=false,facing=north,open=false]","64:4":"minecraft:oak_door[hinge=right,half=lower,powered=false,facing=east,open=true]","64:5":"minecraft:oak_door[hinge=right,half=lower,powered=false,facing=south,open=true]","64:6":"minecraft:oak_door[hinge=right,half=lower,powered=false,facing=west,open=true]","64:7":"minecraft:oak_door[hinge=right,half=lower,powered=false,facing=north,open=true]","64:8":"minecraft:oak_door[hinge=left,half=upper,powered=false,facing=east,open=false]","64:9":"minecraft:oak_door[hinge=right,half=upper,powered=false,facing=east,open=false]","64:10":"minecraft:oak_door[hinge=left,half=upper,powered=true,facing=east,open=false]","64:11":"minecraft:oak_door[hinge=right,half=upper,powered=true,facing=east,open=false]","65:2":"minecraft:ladder[facing=north]","65:3":"minecraft:ladder[facing=south]","65:4":"minecraft:ladder[facing=west]","65:5":"minecraft:ladder[facing=east]","66:0":"minecraft:rail[shape=north_south]","66:1":"minecraft:rail[shape=east_west]","66:2":"minecraft:rail[shape=ascending_east]","66:3":"minecraft:rail[shape=ascending_west]","66:4":"minecraft:rail[shape=ascending_north]","66:5":"minecraft:rail[shape=ascending_south]","66:6":"minecraft:rail[shape=south_east]","66:7":"minecraft:rail[shape=south_west]","66:8":"minecraft:rail[shape=north_west]","66:9":"minecraft:rail[shape=north_east]","67:0":"minecraft:cobblestone_stairs[half=bottom,shape=straight,facing=east]","67:1":"minecraft:cobblestone_stairs[half=bottom,shape=straight,facing=west]","67:2":"minecraft:cobblestone_stairs[half=bottom,shape=straight,facing=south]","67:3":"minecraft:cobblestone_stairs[half=bottom,shape=straight,facing=north]","67:4":"minecraft:cobblestone_stairs[half=top,shape=straight,facing=east]","67:5":"minecraft:cobblestone_stairs[half=top,shape=straight,facing=west]","67:6":"minecraft:cobblestone_stairs[half=top,shape=straight,facing=south]","67:7":"minecraft:cobblestone_stairs[half=top,shape=straight,facing=north]","68:2":"minecraft:wall_sign[facing=north]","68:3":"minecraft:wall_sign[facing=south]","68:4":"minecraft:wall_sign[facing=west]","68:5":"minecraft:wall_sign[facing=east]","69:0":"minecraft:lever[powered=false,facing=north,face=ceiling]","69:1":"minecraft:lever[powered=false,facing=east,face=wall]","69:2":"minecraft:lever[powered=false,facing=west,face=wall]","69:3":"minecraft:lever[powered=false,facing=south,face=wall]","69:4":"minecraft:lever[powered=false,facing=north,face=wall]","69:5":"minecraft:lever[powered=false,facing=east,face=floor]","69:6":"minecraft:lever[powered=false,facing=north,face=floor]","69:7":"minecraft:lever[powered=false,facing=east,face=ceiling]","69:8":"minecraft:lever[powered=true,facing=north,face=ceiling]","69:9":"minecraft:lever[powered=true,facing=east,face=wall]","69:10":"minecraft:lever[powered=true,facing=west,face=wall]","69:11":"minecraft:lever[powered=true,facing=south,face=wall]","69:12":"minecraft:lever[powered=true,facing=north,face=wall]","69:13":"minecraft:lever[powered=true,facing=east,face=floor]","69:14":"minecraft:lever[powered=true,facing=north,face=floor]","69:15":"minecraft:lever[powered=true,facing=east,face=ceiling]","70:0":"minecraft:stone_pressure_plate[powered=false]","70:1":"minecraft:stone_pressure_plate[powered=true]","71:0":"minecraft:iron_door[hinge=right,half=lower,powered=false,facing=east,open=false]","71:1":"minecraft:iron_door[hinge=right,half=lower,powered=false,facing=south,open=false]","71:2":"minecraft:iron_door[hinge=right,half=lower,powered=false,facing=west,open=false]","71:3":"minecraft:iron_door[hinge=right,half=lower,powered=false,facing=north,open=false]","71:4":"minecraft:iron_door[hinge=right,half=lower,powered=false,facing=east,open=true]","71:5":"minecraft:iron_door[hinge=right,half=lower,powered=false,facing=south,open=true]","71:6":"minecraft:iron_door[hinge=right,half=lower,powered=false,facing=west,open=true]","71:7":"minecraft:iron_door[hinge=right,half=lower,powered=false,facing=north,open=true]","71:8":"minecraft:iron_door[hinge=left,half=upper,powered=false,facing=east,open=false]","71:9":"minecraft:iron_door[hinge=right,half=upper,powered=false,facing=east,open=false]","71:10":"minecraft:iron_door[hinge=left,half=upper,powered=true,facing=east,open=false]","71:11":"minecraft:iron_door[hinge=right,half=upper,powered=true,facing=east,open=false]","72:0":"minecraft:oak_pressure_plate[powered=false]","72:1":"minecraft:oak_pressure_plate[powered=true]","73:0":"minecraft:redstone_ore[lit=false]","74:0":"minecraft:redstone_ore[lit=true]","75:1":"minecraft:redstone_wall_torch[facing=east,lit=false]","75:2":"minecraft:redstone_wall_torch[facing=west,lit=false]","75:3":"minecraft:redstone_wall_torch[facing=south,lit=false]","75:4":"minecraft:redstone_wall_torch[facing=north,lit=false]","75:5":"minecraft:redstone_torch[lit=false]","76:1":"minecraft:redstone_wall_torch[facing=east,lit=true]","76:2":"minecraft:redstone_wall_torch[facing=west,lit=true]","76:3":"minecraft:redstone_wall_torch[facing=south,lit=true]","76:4":"minecraft:redstone_wall_torch[facing=north,lit=true]","76:5":"minecraft:redstone_torch[lit=true]","77:0":"minecraft:stone_button[powered=false,facing=east,face=ceiling]","77:1":"minecraft:stone_button[powered=false,facing=east,face=wall]","77:2":"minecraft:stone_button[powered=false,facing=west,face=wall]","77:3":"minecraft:stone_button[powered=false,facing=south,face=wall]","77:4":"minecraft:stone_button[powered=false,facing=north,face=wall]","77:5":"minecraft:stone_button[powered=false,facing=east,face=floor]","77:8":"minecraft:stone_button[powered=true,facing=south,face=ceiling]","77:9":"minecraft:stone_button[powered=true,facing=east,face=wall]","77:10":"minecraft:stone_button[powered=true,facing=west,face=wall]","77:11":"minecraft:stone_button[powered=true,facing=south,face=wall]","77:12":"minecraft:stone_button[powered=true,facing=north,face=wall]","77:13":"minecraft:stone_button[powered=true,facing=south,face=floor]","78:0":"minecraft:snow[layers=1]","78:1":"minecraft:snow[layers=2]","78:2":"minecraft:snow[layers=3]","78:3":"minecraft:snow[layers=4]","78:4":"minecraft:snow[layers=5]","78:5":"minecraft:snow[layers=6]","78:6":"minecraft:snow[layers=7]","78:7":"minecraft:snow[layers=8]","79:0":"minecraft:ice","80:0":"minecraft:snow_block","81:0":"minecraft:cactus[age=0]","81:1":"minecraft:cactus[age=1]","81:2":"minecraft:cactus[age=2]","81:3":"minecraft:cactus[age=3]","81:4":"minecraft:cactus[age=4]","81:5":"minecraft:cactus[age=5]","81:6":"minecraft:cactus[age=6]","81:7":"minecraft:cactus[age=7]","81:8":"minecraft:cactus[age=8]","81:9":"minecraft:cactus[age=9]","81:10":"minecraft:cactus[age=10]","81:11":"minecraft:cactus[age=11]","81:12":"minecraft:cactus[age=12]","81:13":"minecraft:cactus[age=13]","81:14":"minecraft:cactus[age=14]","81:15":"minecraft:cactus[age=15]","82:0":"minecraft:clay","83:0":"minecraft:sugar_cane[age=0]","83:1":"minecraft:sugar_cane[age=1]","83:2":"minecraft:sugar_cane[age=2]","83:3":"minecraft:sugar_cane[age=3]","83:4":"minecraft:sugar_cane[age=4]","83:5":"minecraft:sugar_cane[age=5]","83:6":"minecraft:sugar_cane[age=6]","83:7":"minecraft:sugar_cane[age=7]","83:8":"minecraft:sugar_cane[age=8]","83:9":"minecraft:sugar_cane[age=9]","83:10":"minecraft:sugar_cane[age=10]","83:11":"minecraft:sugar_cane[age=11]","83:12":"minecraft:sugar_cane[age=12]","83:13":"minecraft:sugar_cane[age=13]","83:14":"minecraft:sugar_cane[age=14]","83:15":"minecraft:sugar_cane[age=15]","84:0":"minecraft:jukebox[has_record=false]","84:1":"minecraft:jukebox[has_record=true]","85:0":"minecraft:oak_fence[east=false,south=false,north=false,west=false]","86:0":"minecraft:carved_pumpkin[facing=south]","86:1":"minecraft:carved_pumpkin[facing=west]","86:2":"minecraft:carved_pumpkin[facing=north]","86:3":"minecraft:carved_pumpkin[facing=east]","87:0":"minecraft:netherrack","88:0":"minecraft:soul_sand","89:0":"minecraft:glowstone","90:1":"minecraft:nether_portal[axis=x]","90:2":"minecraft:nether_portal[axis=z]","91:0":"minecraft:jack_o_lantern[facing=south]","91:1":"minecraft:jack_o_lantern[facing=west]","91:2":"minecraft:jack_o_lantern[facing=north]","91:3":"minecraft:jack_o_lantern[facing=east]","92:0":"minecraft:cake[bites=0]","92:1":"minecraft:cake[bites=1]","92:2":"minecraft:cake[bites=2]","92:3":"minecraft:cake[bites=3]","92:4":"minecraft:cake[bites=4]","92:5":"minecraft:cake[bites=5]","92:6":"minecraft:cake[bites=6]","93:0":"minecraft:repeater[delay=1,facing=south,locked=false,powered=false]","93:1":"minecraft:repeater[delay=1,facing=west,locked=false,powered=false]","93:2":"minecraft:repeater[delay=1,facing=north,locked=false,powered=false]","93:3":"minecraft:repeater[delay=1,facing=east,locked=false,powered=false]","93:4":"minecraft:repeater[delay=2,facing=south,locked=false,powered=false]","93:5":"minecraft:repeater[delay=2,facing=west,locked=false,powered=false]","93:6":"minecraft:repeater[delay=2,facing=north,locked=false,powered=false]","93:7":"minecraft:repeater[delay=2,facing=east,locked=false,powered=false]","93:8":"minecraft:repeater[delay=3,facing=south,locked=false,powered=false]","93:9":"minecraft:repeater[delay=3,facing=west,locked=false,powered=false]","93:10":"minecraft:repeater[delay=3,facing=north,locked=false,powered=false]","93:11":"minecraft:repeater[delay=3,facing=east,locked=false,powered=false]","93:12":"minecraft:repeater[delay=4,facing=south,locked=false,powered=false]","93:13":"minecraft:repeater[delay=4,facing=west,locked=false,powered=false]","93:14":"minecraft:repeater[delay=4,facing=north,locked=false,powered=false]","93:15":"minecraft:repeater[delay=4,facing=east,locked=false,powered=false]","94:0":"minecraft:repeater[delay=1,facing=south,locked=false,powered=true]","94:1":"minecraft:repeater[delay=1,facing=west,locked=false,powered=true]","94:2":"minecraft:repeater[delay=1,facing=north,locked=false,powered=true]","94:3":"minecraft:repeater[delay=1,facing=east,locked=false,powered=true]","94:4":"minecraft:repeater[delay=2,facing=south,locked=false,powered=true]","94:5":"minecraft:repeater[delay=2,facing=west,locked=false,powered=true]","94:6":"minecraft:repeater[delay=2,facing=north,locked=false,powered=true]","94:7":"minecraft:repeater[delay=2,facing=east,locked=false,powered=true]","94:8":"minecraft:repeater[delay=3,facing=south,locked=false,powered=true]","94:9":"minecraft:repeater[delay=3,facing=west,locked=false,powered=true]","94:10":"minecraft:repeater[delay=3,facing=north,locked=false,powered=true]","94:11":"minecraft:repeater[delay=3,facing=east,locked=false,powered=true]","94:12":"minecraft:repeater[delay=4,facing=south,locked=false,powered=true]","94:13":"minecraft:repeater[delay=4,facing=west,locked=false,powered=true]","94:14":"minecraft:repeater[delay=4,facing=north,locked=false,powered=true]","94:15":"minecraft:repeater[delay=4,facing=east,locked=false,powered=true]","95:0":"minecraft:white_stained_glass","95:1":"minecraft:orange_stained_glass","95:2":"minecraft:magenta_stained_glass","95:3":"minecraft:light_blue_stained_glass","95:4":"minecraft:yellow_stained_glass","95:5":"minecraft:lime_stained_glass","95:6":"minecraft:pink_stained_glass","95:7":"minecraft:gray_stained_glass","95:8":"minecraft:light_gray_stained_glass","95:9":"minecraft:cyan_stained_glass","95:10":"minecraft:purple_stained_glass","95:11":"minecraft:blue_stained_glass","95:12":"minecraft:brown_stained_glass","95:13":"minecraft:green_stained_glass","95:14":"minecraft:red_stained_glass","95:15":"minecraft:black_stained_glass","96:0":"minecraft:oak_trapdoor[half=bottom,facing=north,open=false,powered=false]","96:1":"minecraft:oak_trapdoor[half=bottom,facing=south,open=false,powered=false]","96:2":"minecraft:oak_trapdoor[half=bottom,facing=west,open=false,powered=false]","96:3":"minecraft:oak_trapdoor[half=bottom,facing=east,open=false,powered=false]","96:4":"minecraft:oak_trapdoor[half=bottom,facing=north,open=true,powered=true]","96:5":"minecraft:oak_trapdoor[half=bottom,facing=south,open=true,powered=true]","96:6":"minecraft:oak_trapdoor[half=bottom,facing=west,open=true,powered=true]","96:7":"minecraft:oak_trapdoor[half=bottom,facing=east,open=true,powered=true]","96:8":"minecraft:oak_trapdoor[half=top,facing=north,open=false,powered=false]","96:9":"minecraft:oak_trapdoor[half=top,facing=south,open=false,powered=false]","96:10":"minecraft:oak_trapdoor[half=top,facing=west,open=false,powered=false]","96:11":"minecraft:oak_trapdoor[half=top,facing=east,open=false,powered=false]","96:12":"minecraft:oak_trapdoor[half=top,facing=north,open=true,powered=true]","96:13":"minecraft:oak_trapdoor[half=top,facing=south,open=true,powered=true]","96:14":"minecraft:oak_trapdoor[half=top,facing=west,open=true,powered=true]","96:15":"minecraft:oak_trapdoor[half=top,facing=east,open=true,powered=true]","97:0":"minecraft:infested_stone","97:1":"minecraft:infested_cobblestone","97:2":"minecraft:infested_stone_bricks","97:3":"minecraft:infested_mossy_stone_bricks","97:4":"minecraft:infested_cracked_stone_bricks","97:5":"minecraft:infested_chiseled_stone_bricks","98:0":"minecraft:stone_bricks","98:1":"minecraft:mossy_stone_bricks","98:2":"minecraft:cracked_stone_bricks","98:3":"minecraft:chiseled_stone_bricks","99:0":"minecraft:brown_mushroom_block[north=false,east=false,south=false,west=false,up=false,down=false]","99:1":"minecraft:brown_mushroom_block[north=true,east=false,south=false,west=true,up=true,down=false]","99:2":"minecraft:brown_mushroom_block[north=true,east=false,south=false,west=false,up=true,down=false]","99:3":"minecraft:brown_mushroom_block[north=true,east=true,south=false,west=false,up=true,down=false]","99:4":"minecraft:brown_mushroom_block[north=false,east=false,south=false,west=true,up=true,down=false]","99:5":"minecraft:brown_mushroom_block[north=false,east=false,south=false,west=false,up=true,down=false]","99:6":"minecraft:brown_mushroom_block[north=false,east=true,south=false,west=false,up=true,down=false]","99:7":"minecraft:brown_mushroom_block[north=false,east=false,south=true,west=true,up=true,down=false]","99:8":"minecraft:brown_mushroom_block[north=false,east=false,south=true,west=false,up=true,down=false]","99:9":"minecraft:brown_mushroom_block[north=false,east=true,south=true,west=false,up=true,down=false]","99:10":"minecraft:mushroom_stem[north=true,east=true,south=true,west=true,up=false,down=false]","99:14":"minecraft:brown_mushroom_block[north=true,east=true,south=true,west=true,up=true,down=true]","99:15":"minecraft:mushroom_stem[north=true,east=true,south=true,west=true,up=true,down=true]","100:0":"minecraft:red_mushroom_block[north=false,east=false,south=false,west=false,up=false,down=false]","100:1":"minecraft:red_mushroom_block[north=true,east=false,south=false,west=true,up=true,down=false]","100:2":"minecraft:red_mushroom_block[north=true,east=false,south=false,west=false,up=true,down=false]","100:3":"minecraft:red_mushroom_block[north=true,east=true,south=false,west=false,up=true,down=false]","100:4":"minecraft:red_mushroom_block[north=false,east=false,south=false,west=true,up=true,down=false]","100:5":"minecraft:red_mushroom_block[north=false,east=false,south=false,west=false,up=true,down=false]","100:6":"minecraft:red_mushroom_block[north=false,east=true,south=false,west=false,up=true,down=false]","100:7":"minecraft:red_mushroom_block[north=false,east=false,south=true,west=true,up=true,down=false]","100:8":"minecraft:red_mushroom_block[north=false,east=false,south=true,west=false,up=true,down=false]","100:9":"minecraft:red_mushroom_block[north=false,east=true,south=true,west=false,up=true,down=false]","100:10":"minecraft:mushroom_stem[north=true,east=true,south=true,west=true,up=false,down=false]","100:14":"minecraft:red_mushroom_block[north=true,east=true,south=true,west=true,up=true,down=true]","100:15":"minecraft:mushroom_stem[north=true,east=true,south=true,west=true,up=true,down=true]","101:0":"minecraft:iron_bars[east=false,south=false,north=false,west=false]","102:0":"minecraft:glass_pane[east=false,south=false,north=false,west=false]","103:0":"minecraft:melon","104:0":"minecraft:pumpkin_stem[age=0]","104:1":"minecraft:pumpkin_stem[age=1]","104:2":"minecraft:pumpkin_stem[age=2]","104:3":"minecraft:pumpkin_stem[age=3]","104:4":"minecraft:pumpkin_stem[age=4]","104:5":"minecraft:pumpkin_stem[age=5]","104:6":"minecraft:pumpkin_stem[age=6]","104:7":"minecraft:pumpkin_stem[age=7]","105:0":"minecraft:melon_stem[age=0]","105:1":"minecraft:melon_stem[age=1]","105:2":"minecraft:melon_stem[age=2]","105:3":"minecraft:melon_stem[age=3]","105:4":"minecraft:melon_stem[age=4]","105:5":"minecraft:melon_stem[age=5]","105:6":"minecraft:melon_stem[age=6]","105:7":"minecraft:melon_stem[age=7]","106:0":"minecraft:vine[east=false,south=false,north=false,west=false,up=false]","106:1":"minecraft:vine[east=false,south=true,north=false,west=false,up=false]","106:2":"minecraft:vine[east=false,south=false,north=false,west=true,up=false]","106:3":"minecraft:vine[east=false,south=true,north=false,west=true,up=false]","106:4":"minecraft:vine[east=false,south=false,north=true,west=false,up=false]","106:5":"minecraft:vine[east=false,south=true,north=true,west=false,up=false]","106:6":"minecraft:vine[east=false,south=false,north=true,west=true,up=false]","106:7":"minecraft:vine[east=false,south=true,north=true,west=true,up=false]","106:8":"minecraft:vine[east=true,south=false,north=false,west=false,up=false]","106:9":"minecraft:vine[east=true,south=true,north=false,west=false,up=false]","106:10":"minecraft:vine[east=true,south=false,north=false,west=true,up=false]","106:11":"minecraft:vine[east=true,south=true,north=false,west=true,up=false]","106:12":"minecraft:vine[east=true,south=false,north=true,west=false,up=false]","106:13":"minecraft:vine[east=true,south=true,north=true,west=false,up=false]","106:14":"minecraft:vine[east=true,south=false,north=true,west=true,up=false]","106:15":"minecraft:vine[east=true,south=true,north=true,west=true,up=false]","107:0":"minecraft:oak_fence_gate[in_wall=false,powered=false,facing=south,open=false]","107:1":"minecraft:oak_fence_gate[in_wall=false,powered=false,facing=west,open=false]","107:2":"minecraft:oak_fence_gate[in_wall=false,powered=false,facing=north,open=false]","107:3":"minecraft:oak_fence_gate[in_wall=false,powered=false,facing=east,open=false]","107:4":"minecraft:oak_fence_gate[in_wall=false,powered=false,facing=south,open=true]","107:5":"minecraft:oak_fence_gate[in_wall=false,powered=false,facing=west,open=true]","107:6":"minecraft:oak_fence_gate[in_wall=false,powered=false,facing=north,open=true]","107:7":"minecraft:oak_fence_gate[in_wall=false,powered=false,facing=east,open=true]","107:8":"minecraft:oak_fence_gate[in_wall=false,powered=true,facing=south,open=false]","107:9":"minecraft:oak_fence_gate[in_wall=false,powered=true,facing=west,open=false]","107:10":"minecraft:oak_fence_gate[in_wall=false,powered=true,facing=north,open=false]","107:11":"minecraft:oak_fence_gate[in_wall=false,powered=true,facing=east,open=false]","107:12":"minecraft:oak_fence_gate[in_wall=false,powered=true,facing=south,open=true]","107:13":"minecraft:oak_fence_gate[in_wall=false,powered=true,facing=west,open=true]","107:14":"minecraft:oak_fence_gate[in_wall=false,powered=true,facing=north,open=true]","107:15":"minecraft:oak_fence_gate[in_wall=false,powered=true,facing=east,open=true]","108:0":"minecraft:brick_stairs[half=bottom,shape=straight,facing=east]","108:1":"minecraft:brick_stairs[half=bottom,shape=straight,facing=west]","108:2":"minecraft:brick_stairs[half=bottom,shape=straight,facing=south]","108:3":"minecraft:brick_stairs[half=bottom,shape=straight,facing=north]","108:4":"minecraft:brick_stairs[half=top,shape=straight,facing=east]","108:5":"minecraft:brick_stairs[half=top,shape=straight,facing=west]","108:6":"minecraft:brick_stairs[half=top,shape=straight,facing=south]","108:7":"minecraft:brick_stairs[half=top,shape=straight,facing=north]","109:0":"minecraft:stone_brick_stairs[half=bottom,shape=straight,facing=east]","109:1":"minecraft:stone_brick_stairs[half=bottom,shape=straight,facing=west]","109:2":"minecraft:stone_brick_stairs[half=bottom,shape=straight,facing=south]","109:3":"minecraft:stone_brick_stairs[half=bottom,shape=straight,facing=north]","109:4":"minecraft:stone_brick_stairs[half=top,shape=straight,facing=east]","109:5":"minecraft:stone_brick_stairs[half=top,shape=straight,facing=west]","109:6":"minecraft:stone_brick_stairs[half=top,shape=straight,facing=south]","109:7":"minecraft:stone_brick_stairs[half=top,shape=straight,facing=north]","110:0":"minecraft:mycelium[snowy=false]","111:0":"minecraft:lily_pad","112:0":"minecraft:nether_bricks","113:0":"minecraft:nether_brick_fence[east=false,south=false,north=false,west=false]","114:0":"minecraft:nether_brick_stairs[half=bottom,shape=straight,facing=east]","114:1":"minecraft:nether_brick_stairs[half=bottom,shape=straight,facing=west]","114:2":"minecraft:nether_brick_stairs[half=bottom,shape=straight,facing=south]","114:3":"minecraft:nether_brick_stairs[half=bottom,shape=straight,facing=north]","114:4":"minecraft:nether_brick_stairs[half=top,shape=straight,facing=east]","114:5":"minecraft:nether_brick_stairs[half=top,shape=straight,facing=west]","114:6":"minecraft:nether_brick_stairs[half=top,shape=straight,facing=south]","114:7":"minecraft:nether_brick_stairs[half=top,shape=straight,facing=north]","115:0":"minecraft:nether_wart[age=0]","115:1":"minecraft:nether_wart[age=1]","115:2":"minecraft:nether_wart[age=2]","115:3":"minecraft:nether_wart[age=3]","116:0":"minecraft:enchanting_table","117:0":"minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]","117:1":"minecraft:brewing_stand[has_bottle_0=true,has_bottle_1=false,has_bottle_2=false]","117:2":"minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=true,has_bottle_2=false]","117:3":"minecraft:brewing_stand[has_bottle_0=true,has_bottle_1=true,has_bottle_2=false]","117:4":"minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=true]","117:5":"minecraft:brewing_stand[has_bottle_0=true,has_bottle_1=false,has_bottle_2=true]","117:6":"minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=true,has_bottle_2=true]","117:7":"minecraft:brewing_stand[has_bottle_0=true,has_bottle_1=true,has_bottle_2=true]","118:0":"minecraft:cauldron[level=0]","118:1":"minecraft:cauldron[level=1]","118:2":"minecraft:cauldron[level=2]","118:3":"minecraft:cauldron[level=3]","119:0":"minecraft:end_portal","120:0":"minecraft:end_portal_frame[eye=false,facing=south]","120:1":"minecraft:end_portal_frame[eye=false,facing=west]","120:2":"minecraft:end_portal_frame[eye=false,facing=north]","120:3":"minecraft:end_portal_frame[eye=false,facing=east]","120:4":"minecraft:end_portal_frame[eye=true,facing=south]","120:5":"minecraft:end_portal_frame[eye=true,facing=west]","120:6":"minecraft:end_portal_frame[eye=true,facing=north]","120:7":"minecraft:end_portal_frame[eye=true,facing=east]","121:0":"minecraft:end_stone","122:0":"minecraft:dragon_egg","123:0":"minecraft:redstone_lamp[lit=false]","124:0":"minecraft:redstone_lamp[lit=true]","125:0":"minecraft:oak_slab[type=double]","125:1":"minecraft:spruce_slab[type=double]","125:2":"minecraft:birch_slab[type=double]","125:3":"minecraft:jungle_slab[type=double]","125:4":"minecraft:acacia_slab[type=double]","125:5":"minecraft:dark_oak_slab[type=double]","126:0":"minecraft:oak_slab[type=bottom]","126:1":"minecraft:spruce_slab[type=bottom]","126:2":"minecraft:birch_slab[type=bottom]","126:3":"minecraft:jungle_slab[type=bottom]","126:4":"minecraft:acacia_slab[type=bottom]","126:5":"minecraft:dark_oak_slab[type=bottom]","126:8":"minecraft:oak_slab[type=top]","126:9":"minecraft:spruce_slab[type=top]","126:10":"minecraft:birch_slab[type=top]","126:11":"minecraft:jungle_slab[type=top]","126:12":"minecraft:acacia_slab[type=top]","126:13":"minecraft:dark_oak_slab[type=top]","127:0":"minecraft:cocoa[facing=south,age=0]","127:1":"minecraft:cocoa[facing=west,age=0]","127:2":"minecraft:cocoa[facing=north,age=0]","127:3":"minecraft:cocoa[facing=east,age=0]","127:4":"minecraft:cocoa[facing=south,age=1]","127:5":"minecraft:cocoa[facing=west,age=1]","127:6":"minecraft:cocoa[facing=north,age=1]","127:7":"minecraft:cocoa[facing=east,age=1]","127:8":"minecraft:cocoa[facing=south,age=2]","127:9":"minecraft:cocoa[facing=west,age=2]","127:10":"minecraft:cocoa[facing=north,age=2]","127:11":"minecraft:cocoa[facing=east,age=2]","128:0":"minecraft:sandstone_stairs[half=bottom,shape=straight,facing=east]","128:1":"minecraft:sandstone_stairs[half=bottom,shape=straight,facing=west]","128:2":"minecraft:sandstone_stairs[half=bottom,shape=straight,facing=south]","128:3":"minecraft:sandstone_stairs[half=bottom,shape=straight,facing=north]","128:4":"minecraft:sandstone_stairs[half=top,shape=straight,facing=east]","128:5":"minecraft:sandstone_stairs[half=top,shape=straight,facing=west]","128:6":"minecraft:sandstone_stairs[half=top,shape=straight,facing=south]","128:7":"minecraft:sandstone_stairs[half=top,shape=straight,facing=north]","129:0":"minecraft:emerald_ore","130:2":"minecraft:ender_chest[facing=north]","130:3":"minecraft:ender_chest[facing=south]","130:4":"minecraft:ender_chest[facing=west]","130:5":"minecraft:ender_chest[facing=east]","131:0":"minecraft:tripwire_hook[powered=false,attached=false,facing=south]","131:1":"minecraft:tripwire_hook[powered=false,attached=false,facing=west]","131:2":"minecraft:tripwire_hook[powered=false,attached=false,facing=north]","131:3":"minecraft:tripwire_hook[powered=false,attached=false,facing=east]","131:4":"minecraft:tripwire_hook[powered=false,attached=true,facing=south]","131:5":"minecraft:tripwire_hook[powered=false,attached=true,facing=west]","131:6":"minecraft:tripwire_hook[powered=false,attached=true,facing=north]","131:7":"minecraft:tripwire_hook[powered=false,attached=true,facing=east]","131:8":"minecraft:tripwire_hook[powered=true,attached=false,facing=south]","131:9":"minecraft:tripwire_hook[powered=true,attached=false,facing=west]","131:10":"minecraft:tripwire_hook[powered=true,attached=false,facing=north]","131:11":"minecraft:tripwire_hook[powered=true,attached=false,facing=east]","131:12":"minecraft:tripwire_hook[powered=true,attached=true,facing=south]","131:13":"minecraft:tripwire_hook[powered=true,attached=true,facing=west]","131:14":"minecraft:tripwire_hook[powered=true,attached=true,facing=north]","131:15":"minecraft:tripwire_hook[powered=true,attached=true,facing=east]","132:0":"minecraft:tripwire[disarmed=false,east=false,powered=false,south=false,north=false,west=false,attached=false]","132:1":"minecraft:tripwire[disarmed=false,east=false,powered=true,south=false,north=false,west=false,attached=false]","132:4":"minecraft:tripwire[disarmed=false,east=false,powered=false,south=false,north=false,west=false,attached=true]","132:5":"minecraft:tripwire[disarmed=false,east=false,powered=true,south=false,north=false,west=false,attached=true]","132:8":"minecraft:tripwire[disarmed=true,east=false,powered=false,south=false,north=false,west=false,attached=false]","132:9":"minecraft:tripwire[disarmed=true,east=false,powered=true,south=false,north=false,west=false,attached=false]","132:12":"minecraft:tripwire[disarmed=true,east=false,powered=false,south=false,north=false,west=false,attached=true]","132:13":"minecraft:tripwire[disarmed=true,east=false,powered=true,south=false,north=false,west=false,attached=true]","133:0":"minecraft:emerald_block","134:0":"minecraft:spruce_stairs[half=bottom,shape=straight,facing=east]","134:1":"minecraft:spruce_stairs[half=bottom,shape=straight,facing=west]","134:2":"minecraft:spruce_stairs[half=bottom,shape=straight,facing=south]","134:3":"minecraft:spruce_stairs[half=bottom,shape=straight,facing=north]","134:4":"minecraft:spruce_stairs[half=top,shape=straight,facing=east]","134:5":"minecraft:spruce_stairs[half=top,shape=straight,facing=west]","134:6":"minecraft:spruce_stairs[half=top,shape=straight,facing=south]","134:7":"minecraft:spruce_stairs[half=top,shape=straight,facing=north]","135:0":"minecraft:birch_stairs[half=bottom,shape=straight,facing=east]","135:1":"minecraft:birch_stairs[half=bottom,shape=straight,facing=west]","135:2":"minecraft:birch_stairs[half=bottom,shape=straight,facing=south]","135:3":"minecraft:birch_stairs[half=bottom,shape=straight,facing=north]","135:4":"minecraft:birch_stairs[half=top,shape=straight,facing=east]","135:5":"minecraft:birch_stairs[half=top,shape=straight,facing=west]","135:6":"minecraft:birch_stairs[half=top,shape=straight,facing=south]","135:7":"minecraft:birch_stairs[half=top,shape=straight,facing=north]","136:0":"minecraft:jungle_stairs[half=bottom,shape=straight,facing=east]","136:1":"minecraft:jungle_stairs[half=bottom,shape=straight,facing=west]","136:2":"minecraft:jungle_stairs[half=bottom,shape=straight,facing=south]","136:3":"minecraft:jungle_stairs[half=bottom,shape=straight,facing=north]","136:4":"minecraft:jungle_stairs[half=top,shape=straight,facing=east]","136:5":"minecraft:jungle_stairs[half=top,shape=straight,facing=west]","136:6":"minecraft:jungle_stairs[half=top,shape=straight,facing=south]","136:7":"minecraft:jungle_stairs[half=top,shape=straight,facing=north]","137:0":"minecraft:command_block[conditional=false,facing=down]","137:1":"minecraft:command_block[conditional=false,facing=up]","137:2":"minecraft:command_block[conditional=false,facing=north]","137:3":"minecraft:command_block[conditional=false,facing=south]","137:4":"minecraft:command_block[conditional=false,facing=west]","137:5":"minecraft:command_block[conditional=false,facing=east]","137:8":"minecraft:command_block[conditional=true,facing=down]","137:9":"minecraft:command_block[conditional=true,facing=up]","137:10":"minecraft:command_block[conditional=true,facing=north]","137:11":"minecraft:command_block[conditional=true,facing=south]","137:12":"minecraft:command_block[conditional=true,facing=west]","137:13":"minecraft:command_block[conditional=true,facing=east]","138:0":"minecraft:beacon","139:0":"minecraft:cobblestone_wall[east=false,south=false,north=false,west=false,up=false]","139:1":"minecraft:mossy_cobblestone_wall[east=false,south=false,north=false,west=false,up=false]","140:0":"minecraft:flower_pot","140:1":"minecraft:potted_poppy","140:2":"minecraft:potted_dandelion","140:3":"minecraft:potted_oak_sapling","140:4":"minecraft:potted_spruce_sapling","140:5":"minecraft:potted_birch_sapling","140:6":"minecraft:potted_jungle_sapling","140:7":"minecraft:potted_red_mushroom","140:8":"minecraft:potted_brown_mushroom","140:9":"minecraft:potted_cactus","140:10":"minecraft:potted_dead_bush","140:11":"minecraft:potted_fern","140:12":"minecraft:potted_acacia_sapling","140:13":"minecraft:potted_dark_oak_sapling","140:14":"minecraft:potted_blue_orchid","140:15":"minecraft:potted_allium","141:0":"minecraft:carrots[age=0]","141:1":"minecraft:carrots[age=1]","141:2":"minecraft:carrots[age=2]","141:3":"minecraft:carrots[age=3]","141:4":"minecraft:carrots[age=4]","141:5":"minecraft:carrots[age=5]","141:6":"minecraft:carrots[age=6]","141:7":"minecraft:carrots[age=7]","142:0":"minecraft:potatoes[age=0]","142:1":"minecraft:potatoes[age=1]","142:2":"minecraft:potatoes[age=2]","142:3":"minecraft:potatoes[age=3]","142:4":"minecraft:potatoes[age=4]","142:5":"minecraft:potatoes[age=5]","142:6":"minecraft:potatoes[age=6]","142:7":"minecraft:potatoes[age=7]","143:0":"minecraft:oak_button[powered=false,facing=east,face=ceiling]","143:1":"minecraft:oak_button[powered=false,facing=east,face=wall]","143:2":"minecraft:oak_button[powered=false,facing=west,face=wall]","143:3":"minecraft:oak_button[powered=false,facing=south,face=wall]","143:4":"minecraft:oak_button[powered=false,facing=north,face=wall]","143:5":"minecraft:oak_button[powered=false,facing=east,face=floor]","143:8":"minecraft:oak_button[powered=true,facing=south,face=ceiling]","143:9":"minecraft:oak_button[powered=true,facing=east,face=wall]","143:10":"minecraft:oak_button[powered=true,facing=west,face=wall]","143:11":"minecraft:oak_button[powered=true,facing=south,face=wall]","143:12":"minecraft:oak_button[powered=true,facing=north,face=wall]","143:13":"minecraft:oak_button[powered=true,facing=south,face=floor]","144:0":"minecraft:skeleton_skull[rotation=0]","144:1":"minecraft:skeleton_skull[rotation=4]","144:2":"minecraft:skeleton_wall_skull[facing=north]","144:3":"minecraft:skeleton_wall_skull[facing=south]","144:4":"minecraft:skeleton_wall_skull[facing=west]","144:5":"minecraft:skeleton_wall_skull[facing=east]","144:8":"minecraft:skeleton_skull[rotation=8]","144:9":"minecraft:skeleton_skull[rotation=12]","144:10":"minecraft:skeleton_wall_skull[facing=north]","144:11":"minecraft:skeleton_wall_skull[facing=south]","144:12":"minecraft:skeleton_wall_skull[facing=west]","144:13":"minecraft:skeleton_wall_skull[facing=east]","145:0":"minecraft:anvil[facing=south]","145:1":"minecraft:anvil[facing=west]","145:2":"minecraft:anvil[facing=north]","145:3":"minecraft:anvil[facing=east]","145:4":"minecraft:chipped_anvil[facing=south]","145:5":"minecraft:chipped_anvil[facing=west]","145:6":"minecraft:chipped_anvil[facing=north]","145:7":"minecraft:chipped_anvil[facing=east]","145:8":"minecraft:damaged_anvil[facing=south]","145:9":"minecraft:damaged_anvil[facing=west]","145:10":"minecraft:damaged_anvil[facing=north]","145:11":"minecraft:damaged_anvil[facing=east]","146:2":"minecraft:trapped_chest[facing=north,type=single]","146:3":"minecraft:trapped_chest[facing=south,type=single]","146:4":"minecraft:trapped_chest[facing=west,type=single]","146:5":"minecraft:trapped_chest[facing=east,type=single]","147:0":"minecraft:light_weighted_pressure_plate[power=0]","147:1":"minecraft:light_weighted_pressure_plate[power=1]","147:2":"minecraft:light_weighted_pressure_plate[power=2]","147:3":"minecraft:light_weighted_pressure_plate[power=3]","147:4":"minecraft:light_weighted_pressure_plate[power=4]","147:5":"minecraft:light_weighted_pressure_plate[power=5]","147:6":"minecraft:light_weighted_pressure_plate[power=6]","147:7":"minecraft:light_weighted_pressure_plate[power=7]","147:8":"minecraft:light_weighted_pressure_plate[power=8]","147:9":"minecraft:light_weighted_pressure_plate[power=9]","147:10":"minecraft:light_weighted_pressure_plate[power=10]","147:11":"minecraft:light_weighted_pressure_plate[power=11]","147:12":"minecraft:light_weighted_pressure_plate[power=12]","147:13":"minecraft:light_weighted_pressure_plate[power=13]","147:14":"minecraft:light_weighted_pressure_plate[power=14]","147:15":"minecraft:light_weighted_pressure_plate[power=15]","148:0":"minecraft:heavy_weighted_pressure_plate[power=0]","148:1":"minecraft:heavy_weighted_pressure_plate[power=1]","148:2":"minecraft:heavy_weighted_pressure_plate[power=2]","148:3":"minecraft:heavy_weighted_pressure_plate[power=3]","148:4":"minecraft:heavy_weighted_pressure_plate[power=4]","148:5":"minecraft:heavy_weighted_pressure_plate[power=5]","148:6":"minecraft:heavy_weighted_pressure_plate[power=6]","148:7":"minecraft:heavy_weighted_pressure_plate[power=7]","148:8":"minecraft:heavy_weighted_pressure_plate[power=8]","148:9":"minecraft:heavy_weighted_pressure_plate[power=9]","148:10":"minecraft:heavy_weighted_pressure_plate[power=10]","148:11":"minecraft:heavy_weighted_pressure_plate[power=11]","148:12":"minecraft:heavy_weighted_pressure_plate[power=12]","148:13":"minecraft:heavy_weighted_pressure_plate[power=13]","148:14":"minecraft:heavy_weighted_pressure_plate[power=14]","148:15":"minecraft:heavy_weighted_pressure_plate[power=15]","149:0":"minecraft:comparator[mode=compare,powered=false,facing=south]","149:1":"minecraft:comparator[mode=compare,powered=false,facing=west]","149:2":"minecraft:comparator[mode=compare,powered=false,facing=north]","149:3":"minecraft:comparator[mode=compare,powered=false,facing=east]","149:4":"minecraft:comparator[mode=subtract,powered=false,facing=south]","149:5":"minecraft:comparator[mode=subtract,powered=false,facing=west]","149:6":"minecraft:comparator[mode=subtract,powered=false,facing=north]","149:7":"minecraft:comparator[mode=subtract,powered=false,facing=east]","149:8":"minecraft:comparator[mode=compare,powered=false,facing=south]","149:9":"minecraft:comparator[mode=compare,powered=false,facing=west]","149:10":"minecraft:comparator[mode=compare,powered=false,facing=north]","149:11":"minecraft:comparator[mode=compare,powered=false,facing=east]","149:12":"minecraft:comparator[mode=subtract,powered=false,facing=south]","149:13":"minecraft:comparator[mode=subtract,powered=false,facing=west]","149:14":"minecraft:comparator[mode=subtract,powered=false,facing=north]","149:15":"minecraft:comparator[mode=subtract,powered=false,facing=east]","150:0":"minecraft:comparator[mode=compare,powered=true,facing=south]","150:1":"minecraft:comparator[mode=compare,powered=true,facing=west]","150:2":"minecraft:comparator[mode=compare,powered=true,facing=north]","150:3":"minecraft:comparator[mode=compare,powered=true,facing=east]","150:4":"minecraft:comparator[mode=subtract,powered=true,facing=south]","150:5":"minecraft:comparator[mode=subtract,powered=true,facing=west]","150:6":"minecraft:comparator[mode=subtract,powered=true,facing=north]","150:7":"minecraft:comparator[mode=subtract,powered=true,facing=east]","150:8":"minecraft:comparator[mode=compare,powered=true,facing=south]","150:9":"minecraft:comparator[mode=compare,powered=true,facing=west]","150:10":"minecraft:comparator[mode=compare,powered=true,facing=north]","150:11":"minecraft:comparator[mode=compare,powered=true,facing=east]","150:12":"minecraft:comparator[mode=subtract,powered=true,facing=south]","150:13":"minecraft:comparator[mode=subtract,powered=true,facing=west]","150:14":"minecraft:comparator[mode=subtract,powered=true,facing=north]","150:15":"minecraft:comparator[mode=subtract,powered=true,facing=east]","151:0":"minecraft:daylight_detector[inverted=false,power=0]","151:1":"minecraft:daylight_detector[inverted=false,power=1]","151:2":"minecraft:daylight_detector[inverted=false,power=2]","151:3":"minecraft:daylight_detector[inverted=false,power=3]","151:4":"minecraft:daylight_detector[inverted=false,power=4]","151:5":"minecraft:daylight_detector[inverted=false,power=5]","151:6":"minecraft:daylight_detector[inverted=false,power=6]","151:7":"minecraft:daylight_detector[inverted=false,power=7]","151:8":"minecraft:daylight_detector[inverted=false,power=8]","151:9":"minecraft:daylight_detector[inverted=false,power=9]","151:10":"minecraft:daylight_detector[inverted=false,power=10]","151:11":"minecraft:daylight_detector[inverted=false,power=11]","151:12":"minecraft:daylight_detector[inverted=false,power=12]","151:13":"minecraft:daylight_detector[inverted=false,power=13]","151:14":"minecraft:daylight_detector[inverted=false,power=14]","151:15":"minecraft:daylight_detector[inverted=false,power=15]","152:0":"minecraft:redstone_block","153:0":"minecraft:nether_quartz_ore","154:0":"minecraft:hopper[facing=down,enabled=true]","154:2":"minecraft:hopper[facing=north,enabled=true]","154:3":"minecraft:hopper[facing=south,enabled=true]","154:4":"minecraft:hopper[facing=west,enabled=true]","154:5":"minecraft:hopper[facing=east,enabled=true]","154:8":"minecraft:hopper[facing=down,enabled=false]","154:10":"minecraft:hopper[facing=north,enabled=false]","154:11":"minecraft:hopper[facing=south,enabled=false]","154:12":"minecraft:hopper[facing=west,enabled=false]","154:13":"minecraft:hopper[facing=east,enabled=false]","155:0":"minecraft:quartz_block","155:1":"minecraft:chiseled_quartz_block","155:2":"minecraft:quartz_pillar[axis=y]","155:3":"minecraft:quartz_pillar[axis=x]","155:4":"minecraft:quartz_pillar[axis=z]","155:6":"minecraft:quartz_pillar[axis=x]","155:10":"minecraft:quartz_pillar[axis=z]","156:0":"minecraft:quartz_stairs[half=bottom,shape=straight,facing=east]","156:1":"minecraft:quartz_stairs[half=bottom,shape=straight,facing=west]","156:2":"minecraft:quartz_stairs[half=bottom,shape=straight,facing=south]","156:3":"minecraft:quartz_stairs[half=bottom,shape=straight,facing=north]","156:4":"minecraft:quartz_stairs[half=top,shape=straight,facing=east]","156:5":"minecraft:quartz_stairs[half=top,shape=straight,facing=west]","156:6":"minecraft:quartz_stairs[half=top,shape=straight,facing=south]","156:7":"minecraft:quartz_stairs[half=top,shape=straight,facing=north]","157:0":"minecraft:activator_rail[shape=north_south,powered=false]","157:1":"minecraft:activator_rail[shape=east_west,powered=false]","157:2":"minecraft:activator_rail[shape=ascending_east,powered=false]","157:3":"minecraft:activator_rail[shape=ascending_west,powered=false]","157:4":"minecraft:activator_rail[shape=ascending_north,powered=false]","157:5":"minecraft:activator_rail[shape=ascending_south,powered=false]","157:8":"minecraft:activator_rail[shape=north_south,powered=true]","157:9":"minecraft:activator_rail[shape=east_west,powered=true]","157:10":"minecraft:activator_rail[shape=ascending_east,powered=true]","157:11":"minecraft:activator_rail[shape=ascending_west,powered=true]","157:12":"minecraft:activator_rail[shape=ascending_north,powered=true]","157:13":"minecraft:activator_rail[shape=ascending_south,powered=true]","158:0":"minecraft:dropper[triggered=false,facing=down]","158:1":"minecraft:dropper[triggered=false,facing=up]","158:2":"minecraft:dropper[triggered=false,facing=north]","158:3":"minecraft:dropper[triggered=false,facing=south]","158:4":"minecraft:dropper[triggered=false,facing=west]","158:5":"minecraft:dropper[triggered=false,facing=east]","158:8":"minecraft:dropper[triggered=true,facing=down]","158:9":"minecraft:dropper[triggered=true,facing=up]","158:10":"minecraft:dropper[triggered=true,facing=north]","158:11":"minecraft:dropper[triggered=true,facing=south]","158:12":"minecraft:dropper[triggered=true,facing=west]","158:13":"minecraft:dropper[triggered=true,facing=east]","159:0":"minecraft:white_terracotta","159:1":"minecraft:orange_terracotta","159:2":"minecraft:magenta_terracotta","159:3":"minecraft:light_blue_terracotta","159:4":"minecraft:yellow_terracotta","159:5":"minecraft:lime_terracotta","159:6":"minecraft:pink_terracotta","159:7":"minecraft:gray_terracotta","159:8":"minecraft:light_gray_terracotta","159:9":"minecraft:cyan_terracotta","159:10":"minecraft:purple_terracotta","159:11":"minecraft:blue_terracotta","159:12":"minecraft:brown_terracotta","159:13":"minecraft:green_terracotta","159:14":"minecraft:red_terracotta","159:15":"minecraft:black_terracotta","160:0":"minecraft:white_stained_glass_pane[east=false,south=false,north=false,west=false]","160:1":"minecraft:orange_stained_glass_pane[east=false,south=false,north=false,west=false]","160:2":"minecraft:magenta_stained_glass_pane[east=false,south=false,north=false,west=false]","160:3":"minecraft:light_blue_stained_glass_pane[east=false,south=false,north=false,west=false]","160:4":"minecraft:yellow_stained_glass_pane[east=false,south=false,north=false,west=false]","160:5":"minecraft:lime_stained_glass_pane[east=false,south=false,north=false,west=false]","160:6":"minecraft:pink_stained_glass_pane[east=false,south=false,north=false,west=false]","160:7":"minecraft:gray_stained_glass_pane[east=false,south=false,north=false,west=false]","160:8":"minecraft:light_gray_stained_glass_pane[east=false,south=false,north=false,west=false]","160:9":"minecraft:cyan_stained_glass_pane[east=false,south=false,north=false,west=false]","160:10":"minecraft:purple_stained_glass_pane[east=false,south=false,north=false,west=false]","160:11":"minecraft:blue_stained_glass_pane[east=false,south=false,north=false,west=false]","160:12":"minecraft:brown_stained_glass_pane[east=false,south=false,north=false,west=false]","160:13":"minecraft:green_stained_glass_pane[east=false,south=false,north=false,west=false]","160:14":"minecraft:red_stained_glass_pane[east=false,south=false,north=false,west=false]","160:15":"minecraft:black_stained_glass_pane[east=false,south=false,north=false,west=false]","161:0":"minecraft:acacia_leaves[persistent=false,distance=1]","161:1":"minecraft:dark_oak_leaves[persistent=false,distance=1]","161:4":"minecraft:acacia_leaves[persistent=true,distance=1]","161:5":"minecraft:dark_oak_leaves[persistent=true,distance=1]","161:8":"minecraft:acacia_leaves[persistent=false,distance=1]","161:9":"minecraft:dark_oak_leaves[persistent=false,distance=1]","161:12":"minecraft:acacia_leaves[persistent=true,distance=1]","161:13":"minecraft:dark_oak_leaves[persistent=true,distance=1]","162:0":"minecraft:acacia_log[axis=y]","162:1":"minecraft:dark_oak_log[axis=y]","162:4":"minecraft:acacia_log[axis=x]","162:5":"minecraft:dark_oak_log[axis=x]","162:8":"minecraft:acacia_log[axis=z]","162:9":"minecraft:dark_oak_log[axis=z]","162:12":"minecraft:acacia_wood","162:13":"minecraft:dark_oak_wood","163:0":"minecraft:acacia_stairs[half=bottom,shape=straight,facing=east]","163:1":"minecraft:acacia_stairs[half=bottom,shape=straight,facing=west]","163:2":"minecraft:acacia_stairs[half=bottom,shape=straight,facing=south]","163:3":"minecraft:acacia_stairs[half=bottom,shape=straight,facing=north]","163:4":"minecraft:acacia_stairs[half=top,shape=straight,facing=east]","163:5":"minecraft:acacia_stairs[half=top,shape=straight,facing=west]","163:6":"minecraft:acacia_stairs[half=top,shape=straight,facing=south]","163:7":"minecraft:acacia_stairs[half=top,shape=straight,facing=north]","164:0":"minecraft:dark_oak_stairs[half=bottom,shape=straight,facing=east]","164:1":"minecraft:dark_oak_stairs[half=bottom,shape=straight,facing=west]","164:2":"minecraft:dark_oak_stairs[half=bottom,shape=straight,facing=south]","164:3":"minecraft:dark_oak_stairs[half=bottom,shape=straight,facing=north]","164:4":"minecraft:dark_oak_stairs[half=top,shape=straight,facing=east]","164:5":"minecraft:dark_oak_stairs[half=top,shape=straight,facing=west]","164:6":"minecraft:dark_oak_stairs[half=top,shape=straight,facing=south]","164:7":"minecraft:dark_oak_stairs[half=top,shape=straight,facing=north]","165:0":"minecraft:slime_block","166:0":"minecraft:barrier","167:0":"minecraft:iron_trapdoor[half=bottom,facing=north,open=false]","167:1":"minecraft:iron_trapdoor[half=bottom,facing=south,open=false]","167:2":"minecraft:iron_trapdoor[half=bottom,facing=west,open=false]","167:3":"minecraft:iron_trapdoor[half=bottom,facing=east,open=false]","167:4":"minecraft:iron_trapdoor[half=bottom,facing=north,open=true]","167:5":"minecraft:iron_trapdoor[half=bottom,facing=south,open=true]","167:6":"minecraft:iron_trapdoor[half=bottom,facing=west,open=true]","167:7":"minecraft:iron_trapdoor[half=bottom,facing=east,open=true]","167:8":"minecraft:iron_trapdoor[half=top,facing=north,open=false]","167:9":"minecraft:iron_trapdoor[half=top,facing=south,open=false]","167:10":"minecraft:iron_trapdoor[half=top,facing=west,open=false]","167:11":"minecraft:iron_trapdoor[half=top,facing=east,open=false]","167:12":"minecraft:iron_trapdoor[half=top,facing=north,open=true]","167:13":"minecraft:iron_trapdoor[half=top,facing=south,open=true]","167:14":"minecraft:iron_trapdoor[half=top,facing=west,open=true]","167:15":"minecraft:iron_trapdoor[half=top,facing=east,open=true]","168:0":"minecraft:prismarine","168:1":"minecraft:prismarine_bricks","168:2":"minecraft:dark_prismarine","169:0":"minecraft:sea_lantern","170:0":"minecraft:hay_block[axis=y]","170:4":"minecraft:hay_block[axis=x]","170:8":"minecraft:hay_block[axis=z]","171:0":"minecraft:white_carpet","171:1":"minecraft:orange_carpet","171:2":"minecraft:magenta_carpet","171:3":"minecraft:light_blue_carpet","171:4":"minecraft:yellow_carpet","171:5":"minecraft:lime_carpet","171:6":"minecraft:pink_carpet","171:7":"minecraft:gray_carpet","171:8":"minecraft:light_gray_carpet","171:9":"minecraft:cyan_carpet","171:10":"minecraft:purple_carpet","171:11":"minecraft:blue_carpet","171:12":"minecraft:brown_carpet","171:13":"minecraft:green_carpet","171:14":"minecraft:red_carpet","171:15":"minecraft:black_carpet","172:0":"minecraft:terracotta","173:0":"minecraft:coal_block","174:0":"minecraft:packed_ice","175:0":"minecraft:sunflower[half=lower]","175:1":"minecraft:lilac[half=lower]","175:2":"minecraft:tall_grass[half=lower]","175:3":"minecraft:large_fern[half=lower]","175:4":"minecraft:rose_bush[half=lower]","175:5":"minecraft:peony[half=lower]","175:8":"minecraft:sunflower[half=upper]","175:9":"minecraft:lilac[half=upper]","175:10":"minecraft:tall_grass[half=upper]","175:11":"minecraft:large_fern[half=upper]","175:12":"minecraft:rose_bush[half=upper]","175:13":"minecraft:peony[half=upper]","176:0":"minecraft:white_banner[rotation=0]","176:1":"minecraft:white_banner[rotation=1]","176:2":"minecraft:white_banner[rotation=2]","176:3":"minecraft:white_banner[rotation=3]","176:4":"minecraft:white_banner[rotation=4]","176:5":"minecraft:white_banner[rotation=5]","176:6":"minecraft:white_banner[rotation=6]","176:7":"minecraft:white_banner[rotation=7]","176:8":"minecraft:white_banner[rotation=8]","176:9":"minecraft:white_banner[rotation=9]","176:10":"minecraft:white_banner[rotation=10]","176:11":"minecraft:white_banner[rotation=11]","176:12":"minecraft:white_banner[rotation=12]","176:13":"minecraft:white_banner[rotation=13]","176:14":"minecraft:white_banner[rotation=14]","176:15":"minecraft:white_banner[rotation=15]","177:2":"minecraft:white_wall_banner[facing=north]","177:3":"minecraft:white_wall_banner[facing=south]","177:4":"minecraft:white_wall_banner[facing=west]","177:5":"minecraft:white_wall_banner[facing=east]","178:0":"minecraft:daylight_detector[inverted=true,power=0]","178:1":"minecraft:daylight_detector[inverted=true,power=1]","178:2":"minecraft:daylight_detector[inverted=true,power=2]","178:3":"minecraft:daylight_detector[inverted=true,power=3]","178:4":"minecraft:daylight_detector[inverted=true,power=4]","178:5":"minecraft:daylight_detector[inverted=true,power=5]","178:6":"minecraft:daylight_detector[inverted=true,power=6]","178:7":"minecraft:daylight_detector[inverted=true,power=7]","178:8":"minecraft:daylight_detector[inverted=true,power=8]","178:9":"minecraft:daylight_detector[inverted=true,power=9]","178:10":"minecraft:daylight_detector[inverted=true,power=10]","178:11":"minecraft:daylight_detector[inverted=true,power=11]","178:12":"minecraft:daylight_detector[inverted=true,power=12]","178:13":"minecraft:daylight_detector[inverted=true,power=13]","178:14":"minecraft:daylight_detector[inverted=true,power=14]","178:15":"minecraft:daylight_detector[inverted=true,power=15]","179:0":"minecraft:red_sandstone","179:1":"minecraft:chiseled_red_sandstone","179:2":"minecraft:cut_red_sandstone","180:0":"minecraft:red_sandstone_stairs[half=bottom,shape=straight,facing=east]","180:1":"minecraft:red_sandstone_stairs[half=bottom,shape=straight,facing=west]","180:2":"minecraft:red_sandstone_stairs[half=bottom,shape=straight,facing=south]","180:3":"minecraft:red_sandstone_stairs[half=bottom,shape=straight,facing=north]","180:4":"minecraft:red_sandstone_stairs[half=top,shape=straight,facing=east]","180:5":"minecraft:red_sandstone_stairs[half=top,shape=straight,facing=west]","180:6":"minecraft:red_sandstone_stairs[half=top,shape=straight,facing=south]","180:7":"minecraft:red_sandstone_stairs[half=top,shape=straight,facing=north]","181:0":"minecraft:red_sandstone_slab[type=double]","181:8":"minecraft:smooth_red_sandstone","182:0":"minecraft:red_sandstone_slab[type=bottom]","182:8":"minecraft:red_sandstone_slab[type=top]","183:0":"minecraft:spruce_fence_gate[in_wall=false,powered=false,facing=south,open=false]","183:1":"minecraft:spruce_fence_gate[in_wall=false,powered=false,facing=west,open=false]","183:2":"minecraft:spruce_fence_gate[in_wall=false,powered=false,facing=north,open=false]","183:3":"minecraft:spruce_fence_gate[in_wall=false,powered=false,facing=east,open=false]","183:4":"minecraft:spruce_fence_gate[in_wall=false,powered=false,facing=south,open=true]","183:5":"minecraft:spruce_fence_gate[in_wall=false,powered=false,facing=west,open=true]","183:6":"minecraft:spruce_fence_gate[in_wall=false,powered=false,facing=north,open=true]","183:7":"minecraft:spruce_fence_gate[in_wall=false,powered=false,facing=east,open=true]","183:8":"minecraft:spruce_fence_gate[in_wall=false,powered=true,facing=south,open=false]","183:9":"minecraft:spruce_fence_gate[in_wall=false,powered=true,facing=west,open=false]","183:10":"minecraft:spruce_fence_gate[in_wall=false,powered=true,facing=north,open=false]","183:11":"minecraft:spruce_fence_gate[in_wall=false,powered=true,facing=east,open=false]","183:12":"minecraft:spruce_fence_gate[in_wall=false,powered=true,facing=south,open=true]","183:13":"minecraft:spruce_fence_gate[in_wall=false,powered=true,facing=west,open=true]","183:14":"minecraft:spruce_fence_gate[in_wall=false,powered=true,facing=north,open=true]","183:15":"minecraft:spruce_fence_gate[in_wall=false,powered=true,facing=east,open=true]","184:0":"minecraft:birch_fence_gate[in_wall=false,powered=false,facing=south,open=false]","184:1":"minecraft:birch_fence_gate[in_wall=false,powered=false,facing=west,open=false]","184:2":"minecraft:birch_fence_gate[in_wall=false,powered=false,facing=north,open=false]","184:3":"minecraft:birch_fence_gate[in_wall=false,powered=false,facing=east,open=false]","184:4":"minecraft:birch_fence_gate[in_wall=false,powered=false,facing=south,open=true]","184:5":"minecraft:birch_fence_gate[in_wall=false,powered=false,facing=west,open=true]","184:6":"minecraft:birch_fence_gate[in_wall=false,powered=false,facing=north,open=true]","184:7":"minecraft:birch_fence_gate[in_wall=false,powered=false,facing=east,open=true]","184:8":"minecraft:birch_fence_gate[in_wall=false,powered=true,facing=south,open=false]","184:9":"minecraft:birch_fence_gate[in_wall=false,powered=true,facing=west,open=false]","184:10":"minecraft:birch_fence_gate[in_wall=false,powered=true,facing=north,open=false]","184:11":"minecraft:birch_fence_gate[in_wall=false,powered=true,facing=east,open=false]","184:12":"minecraft:birch_fence_gate[in_wall=false,powered=true,facing=south,open=true]","184:13":"minecraft:birch_fence_gate[in_wall=false,powered=true,facing=west,open=true]","184:14":"minecraft:birch_fence_gate[in_wall=false,powered=true,facing=north,open=true]","184:15":"minecraft:birch_fence_gate[in_wall=false,powered=true,facing=east,open=true]","185:0":"minecraft:jungle_fence_gate[in_wall=false,powered=false,facing=south,open=false]","185:1":"minecraft:jungle_fence_gate[in_wall=false,powered=false,facing=west,open=false]","185:2":"minecraft:jungle_fence_gate[in_wall=false,powered=false,facing=north,open=false]","185:3":"minecraft:jungle_fence_gate[in_wall=false,powered=false,facing=east,open=false]","185:4":"minecraft:jungle_fence_gate[in_wall=false,powered=false,facing=south,open=true]","185:5":"minecraft:jungle_fence_gate[in_wall=false,powered=false,facing=west,open=true]","185:6":"minecraft:jungle_fence_gate[in_wall=false,powered=false,facing=north,open=true]","185:7":"minecraft:jungle_fence_gate[in_wall=false,powered=false,facing=east,open=true]","185:8":"minecraft:jungle_fence_gate[in_wall=false,powered=true,facing=south,open=false]","185:9":"minecraft:jungle_fence_gate[in_wall=false,powered=true,facing=west,open=false]","185:10":"minecraft:jungle_fence_gate[in_wall=false,powered=true,facing=north,open=false]","185:11":"minecraft:jungle_fence_gate[in_wall=false,powered=true,facing=east,open=false]","185:12":"minecraft:jungle_fence_gate[in_wall=false,powered=true,facing=south,open=true]","185:13":"minecraft:jungle_fence_gate[in_wall=false,powered=true,facing=west,open=true]","185:14":"minecraft:jungle_fence_gate[in_wall=false,powered=true,facing=north,open=true]","185:15":"minecraft:jungle_fence_gate[in_wall=false,powered=true,facing=east,open=true]","186:0":"minecraft:dark_oak_fence_gate[in_wall=false,powered=false,facing=south,open=false]","186:1":"minecraft:dark_oak_fence_gate[in_wall=false,powered=false,facing=west,open=false]","186:2":"minecraft:dark_oak_fence_gate[in_wall=false,powered=false,facing=north,open=false]","186:3":"minecraft:dark_oak_fence_gate[in_wall=false,powered=false,facing=east,open=false]","186:4":"minecraft:dark_oak_fence_gate[in_wall=false,powered=false,facing=south,open=true]","186:5":"minecraft:dark_oak_fence_gate[in_wall=false,powered=false,facing=west,open=true]","186:6":"minecraft:dark_oak_fence_gate[in_wall=false,powered=false,facing=north,open=true]","186:7":"minecraft:dark_oak_fence_gate[in_wall=false,powered=false,facing=east,open=true]","186:8":"minecraft:dark_oak_fence_gate[in_wall=false,powered=true,facing=south,open=false]","186:9":"minecraft:dark_oak_fence_gate[in_wall=false,powered=true,facing=west,open=false]","186:10":"minecraft:dark_oak_fence_gate[in_wall=false,powered=true,facing=north,open=false]","186:11":"minecraft:dark_oak_fence_gate[in_wall=false,powered=true,facing=east,open=false]","186:12":"minecraft:dark_oak_fence_gate[in_wall=false,powered=true,facing=south,open=true]","186:13":"minecraft:dark_oak_fence_gate[in_wall=false,powered=true,facing=west,open=true]","186:14":"minecraft:dark_oak_fence_gate[in_wall=false,powered=true,facing=north,open=true]","186:15":"minecraft:dark_oak_fence_gate[in_wall=false,powered=true,facing=east,open=true]","187:0":"minecraft:acacia_fence_gate[in_wall=false,powered=false,facing=south,open=false]","187:1":"minecraft:acacia_fence_gate[in_wall=false,powered=false,facing=west,open=false]","187:2":"minecraft:acacia_fence_gate[in_wall=false,powered=false,facing=north,open=false]","187:3":"minecraft:acacia_fence_gate[in_wall=false,powered=false,facing=east,open=false]","187:4":"minecraft:acacia_fence_gate[in_wall=false,powered=false,facing=south,open=true]","187:5":"minecraft:acacia_fence_gate[in_wall=false,powered=false,facing=west,open=true]","187:6":"minecraft:acacia_fence_gate[in_wall=false,powered=false,facing=north,open=true]","187:7":"minecraft:acacia_fence_gate[in_wall=false,powered=false,facing=east,open=true]","187:8":"minecraft:acacia_fence_gate[in_wall=false,powered=true,facing=south,open=false]","187:9":"minecraft:acacia_fence_gate[in_wall=false,powered=true,facing=west,open=false]","187:10":"minecraft:acacia_fence_gate[in_wall=false,powered=true,facing=north,open=false]","187:11":"minecraft:acacia_fence_gate[in_wall=false,powered=true,facing=east,open=false]","187:12":"minecraft:acacia_fence_gate[in_wall=false,powered=true,facing=south,open=true]","187:13":"minecraft:acacia_fence_gate[in_wall=false,powered=true,facing=west,open=true]","187:14":"minecraft:acacia_fence_gate[in_wall=false,powered=true,facing=north,open=true]","187:15":"minecraft:acacia_fence_gate[in_wall=false,powered=true,facing=east,open=true]","188:0":"minecraft:spruce_fence[east=false,south=false,north=false,west=false]","189:0":"minecraft:birch_fence[east=false,south=false,north=false,west=false]","190:0":"minecraft:jungle_fence[east=false,south=false,north=false,west=false]","191:0":"minecraft:dark_oak_fence[east=false,south=false,north=false,west=false]","192:0":"minecraft:acacia_fence[east=false,south=false,north=false,west=false]","193:0":"minecraft:spruce_door[hinge=right,half=lower,powered=false,facing=east,open=false]","193:1":"minecraft:spruce_door[hinge=right,half=lower,powered=false,facing=south,open=false]","193:2":"minecraft:spruce_door[hinge=right,half=lower,powered=false,facing=west,open=false]","193:3":"minecraft:spruce_door[hinge=right,half=lower,powered=false,facing=north,open=false]","193:4":"minecraft:spruce_door[hinge=right,half=lower,powered=false,facing=east,open=true]","193:5":"minecraft:spruce_door[hinge=right,half=lower,powered=false,facing=south,open=true]","193:6":"minecraft:spruce_door[hinge=right,half=lower,powered=false,facing=west,open=true]","193:7":"minecraft:spruce_door[hinge=right,half=lower,powered=false,facing=north,open=true]","193:8":"minecraft:spruce_door[hinge=left,half=upper,powered=false,facing=east,open=false]","193:9":"minecraft:spruce_door[hinge=right,half=upper,powered=false,facing=east,open=false]","193:10":"minecraft:spruce_door[hinge=left,half=upper,powered=true,facing=east,open=false]","193:11":"minecraft:spruce_door[hinge=right,half=upper,powered=true,facing=east,open=false]","194:0":"minecraft:birch_door[hinge=right,half=lower,powered=false,facing=east,open=false]","194:1":"minecraft:birch_door[hinge=right,half=lower,powered=false,facing=south,open=false]","194:2":"minecraft:birch_door[hinge=right,half=lower,powered=false,facing=west,open=false]","194:3":"minecraft:birch_door[hinge=right,half=lower,powered=false,facing=north,open=false]","194:4":"minecraft:birch_door[hinge=right,half=lower,powered=false,facing=east,open=true]","194:5":"minecraft:birch_door[hinge=right,half=lower,powered=false,facing=south,open=true]","194:6":"minecraft:birch_door[hinge=right,half=lower,powered=false,facing=west,open=true]","194:7":"minecraft:birch_door[hinge=right,half=lower,powered=false,facing=north,open=true]","194:8":"minecraft:birch_door[hinge=left,half=upper,powered=false,facing=east,open=false]","194:9":"minecraft:birch_door[hinge=right,half=upper,powered=false,facing=east,open=false]","194:10":"minecraft:birch_door[hinge=left,half=upper,powered=true,facing=east,open=false]","194:11":"minecraft:birch_door[hinge=right,half=upper,powered=true,facing=east,open=false]","195:0":"minecraft:jungle_door[hinge=right,half=lower,powered=false,facing=east,open=false]","195:1":"minecraft:jungle_door[hinge=right,half=lower,powered=false,facing=south,open=false]","195:2":"minecraft:jungle_door[hinge=right,half=lower,powered=false,facing=west,open=false]","195:3":"minecraft:jungle_door[hinge=right,half=lower,powered=false,facing=north,open=false]","195:4":"minecraft:jungle_door[hinge=right,half=lower,powered=false,facing=east,open=true]","195:5":"minecraft:jungle_door[hinge=right,half=lower,powered=false,facing=south,open=true]","195:6":"minecraft:jungle_door[hinge=right,half=lower,powered=false,facing=west,open=true]","195:7":"minecraft:jungle_door[hinge=right,half=lower,powered=false,facing=north,open=true]","195:8":"minecraft:jungle_door[hinge=left,half=upper,powered=false,facing=east,open=false]","195:9":"minecraft:jungle_door[hinge=right,half=upper,powered=false,facing=east,open=false]","195:10":"minecraft:jungle_door[hinge=left,half=upper,powered=true,facing=east,open=false]","195:11":"minecraft:jungle_door[hinge=right,half=upper,powered=true,facing=east,open=false]","196:0":"minecraft:acacia_door[hinge=right,half=lower,powered=false,facing=east,open=false]","196:1":"minecraft:acacia_door[hinge=right,half=lower,powered=false,facing=south,open=false]","196:2":"minecraft:acacia_door[hinge=right,half=lower,powered=false,facing=west,open=false]","196:3":"minecraft:acacia_door[hinge=right,half=lower,powered=false,facing=north,open=false]","196:4":"minecraft:acacia_door[hinge=right,half=lower,powered=false,facing=east,open=true]","196:5":"minecraft:acacia_door[hinge=right,half=lower,powered=false,facing=south,open=true]","196:6":"minecraft:acacia_door[hinge=right,half=lower,powered=false,facing=west,open=true]","196:7":"minecraft:acacia_door[hinge=right,half=lower,powered=false,facing=north,open=true]","196:8":"minecraft:acacia_door[hinge=left,half=upper,powered=false,facing=east,open=false]","196:9":"minecraft:acacia_door[hinge=right,half=upper,powered=false,facing=east,open=false]","196:10":"minecraft:acacia_door[hinge=left,half=upper,powered=true,facing=east,open=false]","196:11":"minecraft:acacia_door[hinge=right,half=upper,powered=true,facing=east,open=false]","197:0":"minecraft:dark_oak_door[hinge=right,half=lower,powered=false,facing=east,open=false]","197:1":"minecraft:dark_oak_door[hinge=right,half=lower,powered=false,facing=south,open=false]","197:2":"minecraft:dark_oak_door[hinge=right,half=lower,powered=false,facing=west,open=false]","197:3":"minecraft:dark_oak_door[hinge=right,half=lower,powered=false,facing=north,open=false]","197:4":"minecraft:dark_oak_door[hinge=right,half=lower,powered=false,facing=east,open=true]","197:5":"minecraft:dark_oak_door[hinge=right,half=lower,powered=false,facing=south,open=true]","197:6":"minecraft:dark_oak_door[hinge=right,half=lower,powered=false,facing=west,open=true]","197:7":"minecraft:dark_oak_door[hinge=right,half=lower,powered=false,facing=north,open=true]","197:8":"minecraft:dark_oak_door[hinge=left,half=upper,powered=false,facing=east,open=false]","197:9":"minecraft:dark_oak_door[hinge=right,half=upper,powered=false,facing=east,open=false]","197:10":"minecraft:dark_oak_door[hinge=left,half=upper,powered=true,facing=east,open=false]","197:11":"minecraft:dark_oak_door[hinge=right,half=upper,powered=true,facing=east,open=false]","198:0":"minecraft:end_rod[facing=down]","198:1":"minecraft:end_rod[facing=up]","198:2":"minecraft:end_rod[facing=north]","198:3":"minecraft:end_rod[facing=south]","198:4":"minecraft:end_rod[facing=west]","198:5":"minecraft:end_rod[facing=east]","199:0":"minecraft:chorus_plant[east=false,south=false,north=false,west=false,up=false,down=false]","200:0":"minecraft:chorus_flower[age=0]","200:1":"minecraft:chorus_flower[age=1]","200:2":"minecraft:chorus_flower[age=2]","200:3":"minecraft:chorus_flower[age=3]","200:4":"minecraft:chorus_flower[age=4]","200:5":"minecraft:chorus_flower[age=5]","201:0":"minecraft:purpur_block","202:0":"minecraft:purpur_pillar[axis=y]","202:4":"minecraft:purpur_pillar[axis=x]","202:8":"minecraft:purpur_pillar[axis=z]","203:0":"minecraft:purpur_stairs[half=bottom,shape=straight,facing=east]","203:1":"minecraft:purpur_stairs[half=bottom,shape=straight,facing=west]","203:2":"minecraft:purpur_stairs[half=bottom,shape=straight,facing=south]","203:3":"minecraft:purpur_stairs[half=bottom,shape=straight,facing=north]","203:4":"minecraft:purpur_stairs[half=top,shape=straight,facing=east]","203:5":"minecraft:purpur_stairs[half=top,shape=straight,facing=west]","203:6":"minecraft:purpur_stairs[half=top,shape=straight,facing=south]","203:7":"minecraft:purpur_stairs[half=top,shape=straight,facing=north]","204:0":"minecraft:purpur_slab[type=double]","205:0":"minecraft:purpur_slab[type=bottom]","205:8":"minecraft:purpur_slab[type=top]","206:0":"minecraft:end_stone_bricks","207:0":"minecraft:beetroots[age=0]","207:1":"minecraft:beetroots[age=1]","207:2":"minecraft:beetroots[age=2]","207:3":"minecraft:beetroots[age=3]","208:0":"minecraft:grass_path","209:0":"minecraft:end_gateway","210:0":"minecraft:repeating_command_block[conditional=false,facing=down]","210:1":"minecraft:repeating_command_block[conditional=false,facing=up]","210:2":"minecraft:repeating_command_block[conditional=false,facing=north]","210:3":"minecraft:repeating_command_block[conditional=false,facing=south]","210:4":"minecraft:repeating_command_block[conditional=false,facing=west]","210:5":"minecraft:repeating_command_block[conditional=false,facing=east]","210:8":"minecraft:repeating_command_block[conditional=true,facing=down]","210:9":"minecraft:repeating_command_block[conditional=true,facing=up]","210:10":"minecraft:repeating_command_block[conditional=true,facing=north]","210:11":"minecraft:repeating_command_block[conditional=true,facing=south]","210:12":"minecraft:repeating_command_block[conditional=true,facing=west]","210:13":"minecraft:repeating_command_block[conditional=true,facing=east]","211:0":"minecraft:chain_command_block[conditional=false,facing=down]","211:1":"minecraft:chain_command_block[conditional=false,facing=up]","211:2":"minecraft:chain_command_block[conditional=false,facing=north]","211:3":"minecraft:chain_command_block[conditional=false,facing=south]","211:4":"minecraft:chain_command_block[conditional=false,facing=west]","211:5":"minecraft:chain_command_block[conditional=false,facing=east]","211:8":"minecraft:chain_command_block[conditional=true,facing=down]","211:9":"minecraft:chain_command_block[conditional=true,facing=up]","211:10":"minecraft:chain_command_block[conditional=true,facing=north]","211:11":"minecraft:chain_command_block[conditional=true,facing=south]","211:12":"minecraft:chain_command_block[conditional=true,facing=west]","211:13":"minecraft:chain_command_block[conditional=true,facing=east]","212:0":"minecraft:frosted_ice[age=0]","212:1":"minecraft:frosted_ice[age=1]","212:2":"minecraft:frosted_ice[age=2]","212:3":"minecraft:frosted_ice[age=3]","213:0":"minecraft:magma_block","214:0":"minecraft:nether_wart_block","215:0":"minecraft:red_nether_bricks","216:0":"minecraft:bone_block[axis=y]","216:4":"minecraft:bone_block[axis=x]","216:8":"minecraft:bone_block[axis=z]","217:0":"minecraft:structure_void","218:0":"minecraft:observer[powered=false,facing=down]","218:1":"minecraft:observer[powered=false,facing=up]","218:2":"minecraft:observer[powered=false,facing=north]","218:3":"minecraft:observer[powered=false,facing=south]","218:4":"minecraft:observer[powered=false,facing=west]","218:5":"minecraft:observer[powered=false,facing=east]","218:8":"minecraft:observer[powered=true,facing=down]","218:9":"minecraft:observer[powered=true,facing=up]","218:10":"minecraft:observer[powered=true,facing=north]","218:11":"minecraft:observer[powered=true,facing=south]","218:12":"minecraft:observer[powered=true,facing=west]","218:13":"minecraft:observer[powered=true,facing=east]","219:0":"minecraft:white_shulker_box[facing=down]","219:1":"minecraft:white_shulker_box[facing=up]","219:2":"minecraft:white_shulker_box[facing=north]","219:3":"minecraft:white_shulker_box[facing=south]","219:4":"minecraft:white_shulker_box[facing=west]","219:5":"minecraft:white_shulker_box[facing=east]","220:0":"minecraft:orange_shulker_box[facing=down]","220:1":"minecraft:orange_shulker_box[facing=up]","220:2":"minecraft:orange_shulker_box[facing=north]","220:3":"minecraft:orange_shulker_box[facing=south]","220:4":"minecraft:orange_shulker_box[facing=west]","220:5":"minecraft:orange_shulker_box[facing=east]","221:0":"minecraft:magenta_shulker_box[facing=down]","221:1":"minecraft:magenta_shulker_box[facing=up]","221:2":"minecraft:magenta_shulker_box[facing=north]","221:3":"minecraft:magenta_shulker_box[facing=south]","221:4":"minecraft:magenta_shulker_box[facing=west]","221:5":"minecraft:magenta_shulker_box[facing=east]","222:0":"minecraft:light_blue_shulker_box[facing=down]","222:1":"minecraft:light_blue_shulker_box[facing=up]","222:2":"minecraft:light_blue_shulker_box[facing=north]","222:3":"minecraft:light_blue_shulker_box[facing=south]","222:4":"minecraft:light_blue_shulker_box[facing=west]","222:5":"minecraft:light_blue_shulker_box[facing=east]","223:0":"minecraft:yellow_shulker_box[facing=down]","223:1":"minecraft:yellow_shulker_box[facing=up]","223:2":"minecraft:yellow_shulker_box[facing=north]","223:3":"minecraft:yellow_shulker_box[facing=south]","223:4":"minecraft:yellow_shulker_box[facing=west]","223:5":"minecraft:yellow_shulker_box[facing=east]","224:0":"minecraft:lime_shulker_box[facing=down]","224:1":"minecraft:lime_shulker_box[facing=up]","224:2":"minecraft:lime_shulker_box[facing=north]","224:3":"minecraft:lime_shulker_box[facing=south]","224:4":"minecraft:lime_shulker_box[facing=west]","224:5":"minecraft:lime_shulker_box[facing=east]","225:0":"minecraft:pink_shulker_box[facing=down]","225:1":"minecraft:pink_shulker_box[facing=up]","225:2":"minecraft:pink_shulker_box[facing=north]","225:3":"minecraft:pink_shulker_box[facing=south]","225:4":"minecraft:pink_shulker_box[facing=west]","225:5":"minecraft:pink_shulker_box[facing=east]","226:0":"minecraft:gray_shulker_box[facing=down]","226:1":"minecraft:gray_shulker_box[facing=up]","226:2":"minecraft:gray_shulker_box[facing=north]","226:3":"minecraft:gray_shulker_box[facing=south]","226:4":"minecraft:gray_shulker_box[facing=west]","226:5":"minecraft:gray_shulker_box[facing=east]","227:0":"minecraft:light_gray_shulker_box[facing=down]","227:1":"minecraft:light_gray_shulker_box[facing=up]","227:2":"minecraft:light_gray_shulker_box[facing=north]","227:3":"minecraft:light_gray_shulker_box[facing=south]","227:4":"minecraft:light_gray_shulker_box[facing=west]","227:5":"minecraft:light_gray_shulker_box[facing=east]","228:0":"minecraft:cyan_shulker_box[facing=down]","228:1":"minecraft:cyan_shulker_box[facing=up]","228:2":"minecraft:cyan_shulker_box[facing=north]","228:3":"minecraft:cyan_shulker_box[facing=south]","228:4":"minecraft:cyan_shulker_box[facing=west]","228:5":"minecraft:cyan_shulker_box[facing=east]","229:0":"minecraft:purple_shulker_box[facing=down]","229:1":"minecraft:purple_shulker_box[facing=up]","229:2":"minecraft:purple_shulker_box[facing=north]","229:3":"minecraft:purple_shulker_box[facing=south]","229:4":"minecraft:purple_shulker_box[facing=west]","229:5":"minecraft:purple_shulker_box[facing=east]","230:0":"minecraft:blue_shulker_box[facing=down]","230:1":"minecraft:blue_shulker_box[facing=up]","230:2":"minecraft:blue_shulker_box[facing=north]","230:3":"minecraft:blue_shulker_box[facing=south]","230:4":"minecraft:blue_shulker_box[facing=west]","230:5":"minecraft:blue_shulker_box[facing=east]","231:0":"minecraft:brown_shulker_box[facing=down]","231:1":"minecraft:brown_shulker_box[facing=up]","231:2":"minecraft:brown_shulker_box[facing=north]","231:3":"minecraft:brown_shulker_box[facing=south]","231:4":"minecraft:brown_shulker_box[facing=west]","231:5":"minecraft:brown_shulker_box[facing=east]","232:0":"minecraft:green_shulker_box[facing=down]","232:1":"minecraft:green_shulker_box[facing=up]","232:2":"minecraft:green_shulker_box[facing=north]","232:3":"minecraft:green_shulker_box[facing=south]","232:4":"minecraft:green_shulker_box[facing=west]","232:5":"minecraft:green_shulker_box[facing=east]","233:0":"minecraft:red_shulker_box[facing=down]","233:1":"minecraft:red_shulker_box[facing=up]","233:2":"minecraft:red_shulker_box[facing=north]","233:3":"minecraft:red_shulker_box[facing=south]","233:4":"minecraft:red_shulker_box[facing=west]","233:5":"minecraft:red_shulker_box[facing=east]","234:0":"minecraft:black_shulker_box[facing=down]","234:1":"minecraft:black_shulker_box[facing=up]","234:2":"minecraft:black_shulker_box[facing=north]","234:3":"minecraft:black_shulker_box[facing=south]","234:4":"minecraft:black_shulker_box[facing=west]","234:5":"minecraft:black_shulker_box[facing=east]","235:0":"minecraft:white_glazed_terracotta[facing=south]","235:1":"minecraft:white_glazed_terracotta[facing=west]","235:2":"minecraft:white_glazed_terracotta[facing=north]","235:3":"minecraft:white_glazed_terracotta[facing=east]","236:0":"minecraft:orange_glazed_terracotta[facing=south]","236:1":"minecraft:orange_glazed_terracotta[facing=west]","236:2":"minecraft:orange_glazed_terracotta[facing=north]","236:3":"minecraft:orange_glazed_terracotta[facing=east]","237:0":"minecraft:magenta_glazed_terracotta[facing=south]","237:1":"minecraft:magenta_glazed_terracotta[facing=west]","237:2":"minecraft:magenta_glazed_terracotta[facing=north]","237:3":"minecraft:magenta_glazed_terracotta[facing=east]","238:0":"minecraft:light_blue_glazed_terracotta[facing=south]","238:1":"minecraft:light_blue_glazed_terracotta[facing=west]","238:2":"minecraft:light_blue_glazed_terracotta[facing=north]","238:3":"minecraft:light_blue_glazed_terracotta[facing=east]","239:0":"minecraft:yellow_glazed_terracotta[facing=south]","239:1":"minecraft:yellow_glazed_terracotta[facing=west]","239:2":"minecraft:yellow_glazed_terracotta[facing=north]","239:3":"minecraft:yellow_glazed_terracotta[facing=east]","240:0":"minecraft:lime_glazed_terracotta[facing=south]","240:1":"minecraft:lime_glazed_terracotta[facing=west]","240:2":"minecraft:lime_glazed_terracotta[facing=north]","240:3":"minecraft:lime_glazed_terracotta[facing=east]","241:0":"minecraft:pink_glazed_terracotta[facing=south]","241:1":"minecraft:pink_glazed_terracotta[facing=west]","241:2":"minecraft:pink_glazed_terracotta[facing=north]","241:3":"minecraft:pink_glazed_terracotta[facing=east]","242:0":"minecraft:gray_glazed_terracotta[facing=south]","242:1":"minecraft:gray_glazed_terracotta[facing=west]","242:2":"minecraft:gray_glazed_terracotta[facing=north]","242:3":"minecraft:gray_glazed_terracotta[facing=east]","243:0":"minecraft:light_gray_glazed_terracotta[facing=south]","243:1":"minecraft:light_gray_glazed_terracotta[facing=west]","243:2":"minecraft:light_gray_glazed_terracotta[facing=north]","243:3":"minecraft:light_gray_glazed_terracotta[facing=east]","244:0":"minecraft:cyan_glazed_terracotta[facing=south]","244:1":"minecraft:cyan_glazed_terracotta[facing=west]","244:2":"minecraft:cyan_glazed_terracotta[facing=north]","244:3":"minecraft:cyan_glazed_terracotta[facing=east]","245:0":"minecraft:purple_glazed_terracotta[facing=south]","245:1":"minecraft:purple_glazed_terracotta[facing=west]","245:2":"minecraft:purple_glazed_terracotta[facing=north]","245:3":"minecraft:purple_glazed_terracotta[facing=east]","246:0":"minecraft:blue_glazed_terracotta[facing=south]","246:1":"minecraft:blue_glazed_terracotta[facing=west]","246:2":"minecraft:blue_glazed_terracotta[facing=north]","246:3":"minecraft:blue_glazed_terracotta[facing=east]","247:0":"minecraft:brown_glazed_terracotta[facing=south]","247:1":"minecraft:brown_glazed_terracotta[facing=west]","247:2":"minecraft:brown_glazed_terracotta[facing=north]","247:3":"minecraft:brown_glazed_terracotta[facing=east]","248:0":"minecraft:green_glazed_terracotta[facing=south]","248:1":"minecraft:green_glazed_terracotta[facing=west]","248:2":"minecraft:green_glazed_terracotta[facing=north]","248:3":"minecraft:green_glazed_terracotta[facing=east]","249:0":"minecraft:red_glazed_terracotta[facing=south]","249:1":"minecraft:red_glazed_terracotta[facing=west]","249:2":"minecraft:red_glazed_terracotta[facing=north]","249:3":"minecraft:red_glazed_terracotta[facing=east]","250:0":"minecraft:black_glazed_terracotta[facing=south]","250:1":"minecraft:black_glazed_terracotta[facing=west]","250:2":"minecraft:black_glazed_terracotta[facing=north]","250:3":"minecraft:black_glazed_terracotta[facing=east]","251:0":"minecraft:white_concrete","251:1":"minecraft:orange_concrete","251:2":"minecraft:magenta_concrete","251:3":"minecraft:light_blue_concrete","251:4":"minecraft:yellow_concrete","251:5":"minecraft:lime_concrete","251:6":"minecraft:pink_concrete","251:7":"minecraft:gray_concrete","251:8":"minecraft:light_gray_concrete","251:9":"minecraft:cyan_concrete","251:10":"minecraft:purple_concrete","251:11":"minecraft:blue_concrete","251:12":"minecraft:brown_concrete","251:13":"minecraft:green_concrete","251:14":"minecraft:red_concrete","251:15":"minecraft:black_concrete","252:0":"minecraft:white_concrete_powder","252:1":"minecraft:orange_concrete_powder","252:2":"minecraft:magenta_concrete_powder","252:3":"minecraft:light_blue_concrete_powder","252:4":"minecraft:yellow_concrete_powder","252:5":"minecraft:lime_concrete_powder","252:6":"minecraft:pink_concrete_powder","252:7":"minecraft:gray_concrete_powder","252:8":"minecraft:light_gray_concrete_powder","252:9":"minecraft:cyan_concrete_powder","252:10":"minecraft:purple_concrete_powder","252:11":"minecraft:blue_concrete_powder","252:12":"minecraft:brown_concrete_powder","252:13":"minecraft:green_concrete_powder","252:14":"minecraft:red_concrete_powder","252:15":"minecraft:black_concrete_powder","255:0":"minecraft:structure_block[mode=save]","255:1":"minecraft:structure_block[mode=load]","255:2":"minecraft:structure_block[mode=corner]","255:3":"minecraft:structure_block[mode=data]"},"items":{"0:0":"minecraft:air","1:0":"minecraft:stone","1:1":"minecraft:granite","1:2":"minecraft:polished_granite","1:3":"minecraft:diorite","1:4":"minecraft:polished_diorite","1:5":"minecraft:andesite","1:6":"minecraft:polished_andesite","2:0":"minecraft:grass_block","3:0":"minecraft:dirt","3:1":"minecraft:coarse_dirt","3:2":"minecraft:podzol","4:0":"minecraft:cobblestone","5:0":"minecraft:oak_planks","5:1":"minecraft:spruce_planks","5:2":"minecraft:birch_planks","5:3":"minecraft:jungle_planks","5:4":"minecraft:acacia_planks","5:5":"minecraft:dark_oak_planks","6:0":"minecraft:oak_sapling","6:1":"minecraft:spruce_sapling","6:2":"minecraft:birch_sapling","6:3":"minecraft:jungle_sapling","6:4":"minecraft:acacia_sapling","6:5":"minecraft:dark_oak_sapling","7:0":"minecraft:bedrock","12:0":"minecraft:sand","12:1":"minecraft:red_sand","13:0":"minecraft:gravel","14:0":"minecraft:gold_ore","15:0":"minecraft:iron_ore","16:0":"minecraft:coal_ore","17:0":"minecraft:oak_log","17:1":"minecraft:spruce_log","17:2":"minecraft:birch_log","17:3":"minecraft:jungle_log","18:0":"minecraft:oak_leaves","18:1":"minecraft:spruce_leaves","18:2":"minecraft:birch_leaves","18:3":"minecraft:jungle_leaves","19:0":"minecraft:sponge","19:1":"minecraft:wet_sponge","20:0":"minecraft:glass","21:0":"minecraft:lapis_ore","22:0":"minecraft:lapis_block","23:0":"minecraft:dispenser","24:0":"minecraft:sandstone","24:1":"minecraft:chiseled_sandstone","24:2":"minecraft:cut_sandstone","25:0":"minecraft:note_block","27:0":"minecraft:powered_rail","28:0":"minecraft:detector_rail","29:0":"minecraft:sticky_piston","30:0":"minecraft:cobweb","31:1":"minecraft:grass","31:2":"minecraft:fern","32:0":"minecraft:dead_bush","33:0":"minecraft:piston","35:0":"minecraft:white_wool","35:1":"minecraft:orange_wool","35:2":"minecraft:magenta_wool","35:3":"minecraft:light_blue_wool","35:4":"minecraft:yellow_wool","35:5":"minecraft:lime_wool","35:6":"minecraft:pink_wool","35:7":"minecraft:gray_wool","35:8":"minecraft:light_gray_wool","35:9":"minecraft:cyan_wool","35:10":"minecraft:purple_wool","35:11":"minecraft:blue_wool","35:12":"minecraft:brown_wool","35:13":"minecraft:green_wool","35:14":"minecraft:red_wool","35:15":"minecraft:black_wool","37:0":"minecraft:dandelion","38:0":"minecraft:poppy","38:1":"minecraft:blue_orchid","38:2":"minecraft:allium","38:3":"minecraft:azure_bluet","38:4":"minecraft:red_tulip","38:5":"minecraft:orange_tulip","38:6":"minecraft:white_tulip","38:7":"minecraft:pink_tulip","38:8":"minecraft:oxeye_daisy","39:0":"minecraft:brown_mushroom","40:0":"minecraft:red_mushroom","41:0":"minecraft:gold_block","42:0":"minecraft:iron_block","44:0":"minecraft:stone_slab","44:1":"minecraft:sandstone_slab","44:3":"minecraft:cobblestone_slab","44:4":"minecraft:brick_slab","44:5":"minecraft:stone_brick_slab","44:6":"minecraft:nether_brick_slab","44:7":"minecraft:quartz_slab","45:0":"minecraft:bricks","46:0":"minecraft:tnt","47:0":"minecraft:bookshelf","48:0":"minecraft:mossy_cobblestone","49:0":"minecraft:obsidian","50:0":"minecraft:torch","52:0":"minecraft:spawner","53:0":"minecraft:oak_stairs","54:0":"minecraft:chest","56:0":"minecraft:diamond_ore","57:0":"minecraft:diamond_block","58:0":"minecraft:crafting_table","60:0":"minecraft:farmland","61:0":"minecraft:furnace","65:0":"minecraft:ladder","66:0":"minecraft:rail","67:0":"minecraft:cobblestone_stairs","69:0":"minecraft:lever","70:0":"minecraft:stone_pressure_plate","72:0":"minecraft:oak_pressure_plate","73:0":"minecraft:redstone_ore","76:0":"minecraft:redstone_torch","77:0":"minecraft:stone_button","78:0":"minecraft:snow","79:0":"minecraft:ice","80:0":"minecraft:snow_block","81:0":"minecraft:cactus","82:0":"minecraft:clay","84:0":"minecraft:jukebox","85:0":"minecraft:oak_fence","86:0":"minecraft:carved_pumpkin","87:0":"minecraft:netherrack","88:0":"minecraft:soul_sand","89:0":"minecraft:glowstone","91:0":"minecraft:jack_o_lantern","95:0":"minecraft:white_stained_glass","95:1":"minecraft:orange_stained_glass","95:2":"minecraft:magenta_stained_glass","95:3":"minecraft:light_blue_stained_glass","95:4":"minecraft:yellow_stained_glass","95:5":"minecraft:lime_stained_glass","95:6":"minecraft:pink_stained_glass","95:7":"minecraft:gray_stained_glass","95:8":"minecraft:light_gray_stained_glass","95:9":"minecraft:cyan_stained_glass","95:10":"minecraft:purple_stained_glass","95:11":"minecraft:blue_stained_glass","95:12":"minecraft:brown_stained_glass","95:13":"minecraft:green_stained_glass","95:14":"minecraft:red_stained_glass","95:15":"minecraft:black_stained_glass","96:0":"minecraft:oak_trapdoor","97:0":"minecraft:infested_stone","97:1":"minecraft:infested_cobblestone","97:2":"minecraft:infested_stone_bricks","97:3":"minecraft:infested_mossy_stone_bricks","97:4":"minecraft:infested_cracked_stone_bricks","97:5":"minecraft:infested_chiseled_stone_bricks","98:0":"minecraft:stone_bricks","98:1":"minecraft:mossy_stone_bricks","98:2":"minecraft:cracked_stone_bricks","98:3":"minecraft:chiseled_stone_bricks","99:0":"minecraft:brown_mushroom_block","100:0":"minecraft:red_mushroom_block","101:0":"minecraft:iron_bars","102:0":"minecraft:glass_pane","103:0":"minecraft:melon","106:0":"minecraft:vine","107:0":"minecraft:oak_fence_gate","108:0":"minecraft:brick_stairs","109:0":"minecraft:stone_brick_stairs","110:0":"minecraft:mycelium","111:0":"minecraft:lily_pad","112:0":"minecraft:nether_bricks","113:0":"minecraft:nether_brick_fence","114:0":"minecraft:nether_brick_stairs","116:0":"minecraft:enchanting_table","120:0":"minecraft:end_portal_frame","121:0":"minecraft:end_stone","122:0":"minecraft:dragon_egg","123:0":"minecraft:redstone_lamp","126:0":"minecraft:oak_slab","126:1":"minecraft:spruce_slab","126:2":"minecraft:birch_slab","126:3":"minecraft:jungle_slab","126:4":"minecraft:acacia_slab","126:5":"minecraft:dark_oak_slab","128:0":"minecraft:sandstone_stairs","129:0":"minecraft:emerald_ore","130:0":"minecraft:ender_chest","131:0":"minecraft:tripwire_hook","133:0":"minecraft:emerald_block","134:0":"minecraft:spruce_stairs","135:0":"minecraft:birch_stairs","136:0":"minecraft:jungle_stairs","137:0":"minecraft:command_block","138:0":"minecraft:beacon","139:0":"minecraft:cobblestone_wall","139:1":"minecraft:mossy_cobblestone_wall","143:0":"minecraft:oak_button","145:0":"minecraft:anvil","145:1":"minecraft:chipped_anvil","145:2":"minecraft:damaged_anvil","146:0":"minecraft:trapped_chest","147:0":"minecraft:light_weighted_pressure_plate","148:0":"minecraft:heavy_weighted_pressure_plate","151:0":"minecraft:daylight_detector","152:0":"minecraft:redstone_block","153:0":"minecraft:nether_quartz_ore","154:0":"minecraft:hopper","155:0":"minecraft:quartz_block","155:1":"minecraft:chiseled_quartz_block","155:2":"minecraft:quartz_pillar","156:0":"minecraft:quartz_stairs","157:0":"minecraft:activator_rail","158:0":"minecraft:dropper","159:0":"minecraft:white_terracotta","159:1":"minecraft:orange_terracotta","159:2":"minecraft:magenta_terracotta","159:3":"minecraft:light_blue_terracotta","159:4":"minecraft:yellow_terracotta","159:5":"minecraft:lime_terracotta","159:6":"minecraft:pink_terracotta","159:7":"minecraft:gray_terracotta","159:8":"minecraft:light_gray_terracotta","159:9":"minecraft:cyan_terracotta","159:10":"minecraft:purple_terracotta","159:11":"minecraft:blue_terracotta","159:12":"minecraft:brown_terracotta","159:13":"minecraft:green_terracotta","159:14":"minecraft:red_terracotta","159:15":"minecraft:black_terracotta","160:0":"minecraft:white_stained_glass_pane","160:1":"minecraft:orange_stained_glass_pane","160:2":"minecraft:magenta_stained_glass_pane","160:3":"minecraft:light_blue_stained_glass_pane","160:4":"minecraft:yellow_stained_glass_pane","160:5":"minecraft:lime_stained_glass_pane","160:6":"minecraft:pink_stained_glass_pane","160:7":"minecraft:gray_stained_glass_pane","160:8":"minecraft:light_gray_stained_glass_pane","160:9":"minecraft:cyan_stained_glass_pane","160:10":"minecraft:purple_stained_glass_pane","160:11":"minecraft:blue_stained_glass_pane","160:12":"minecraft:brown_stained_glass_pane","160:13":"minecraft:green_stained_glass_pane","160:14":"minecraft:red_stained_glass_pane","160:15":"minecraft:black_stained_glass_pane","161:0":"minecraft:acacia_leaves","161:1":"minecraft:dark_oak_leaves","162:0":"minecraft:acacia_log","162:1":"minecraft:dark_oak_log","163:0":"minecraft:acacia_stairs","164:0":"minecraft:dark_oak_stairs","165:0":"minecraft:slime_block","166:0":"minecraft:barrier","167:0":"minecraft:iron_trapdoor","168:0":"minecraft:prismarine","168:1":"minecraft:prismarine_bricks","168:2":"minecraft:dark_prismarine","169:0":"minecraft:sea_lantern","170:0":"minecraft:hay_block","171:0":"minecraft:white_carpet","171:1":"minecraft:orange_carpet","171:2":"minecraft:magenta_carpet","171:3":"minecraft:light_blue_carpet","171:4":"minecraft:yellow_carpet","171:5":"minecraft:lime_carpet","171:6":"minecraft:pink_carpet","171:7":"minecraft:gray_carpet","171:8":"minecraft:light_gray_carpet","171:9":"minecraft:cyan_carpet","171:10":"minecraft:purple_carpet","171:11":"minecraft:blue_carpet","171:12":"minecraft:brown_carpet","171:13":"minecraft:green_carpet","171:14":"minecraft:red_carpet","171:15":"minecraft:black_carpet","172:0":"minecraft:terracotta","173:0":"minecraft:coal_block","174:0":"minecraft:packed_ice","175:0":"minecraft:sunflower","175:1":"minecraft:lilac","175:2":"minecraft:tall_grass","175:3":"minecraft:large_fern","175:4":"minecraft:rose_bush","175:5":"minecraft:peony","179:0":"minecraft:red_sandstone","179:1":"minecraft:chiseled_red_sandstone","179:2":"minecraft:cut_red_sandstone","180:0":"minecraft:red_sandstone_stairs","182:0":"minecraft:red_sandstone_slab","183:0":"minecraft:spruce_fence_gate","184:0":"minecraft:birch_fence_gate","185:0":"minecraft:jungle_fence_gate","186:0":"minecraft:dark_oak_fence_gate","187:0":"minecraft:acacia_fence_gate","188:0":"minecraft:spruce_fence","189:0":"minecraft:birch_fence","190:0":"minecraft:jungle_fence","191:0":"minecraft:dark_oak_fence","192:0":"minecraft:acacia_fence","198:0":"minecraft:end_rod","199:0":"minecraft:chorus_plant","200:0":"minecraft:chorus_flower","201:0":"minecraft:purpur_block","202:0":"minecraft:purpur_pillar","203:0":"minecraft:purpur_stairs","205:0":"minecraft:purpur_slab","206:0":"minecraft:end_stone_bricks","208:0":"minecraft:grass_path","210:0":"minecraft:repeating_command_block","211:0":"minecraft:chain_command_block","213:0":"minecraft:magma_block","214:0":"minecraft:nether_wart_block","215:0":"minecraft:red_nether_bricks","216:0":"minecraft:bone_block","217:0":"minecraft:structure_void","218:0":"minecraft:observer","219:0":"minecraft:white_shulker_box","220:0":"minecraft:orange_shulker_box","221:0":"minecraft:magenta_shulker_box","222:0":"minecraft:light_blue_shulker_box","223:0":"minecraft:yellow_shulker_box","224:0":"minecraft:lime_shulker_box","225:0":"minecraft:pink_shulker_box","226:0":"minecraft:gray_shulker_box","227:0":"minecraft:light_gray_shulker_box","228:0":"minecraft:cyan_shulker_box","229:0":"minecraft:purple_shulker_box","230:0":"minecraft:blue_shulker_box","231:0":"minecraft:brown_shulker_box","232:0":"minecraft:green_shulker_box","233:0":"minecraft:red_shulker_box","234:0":"minecraft:black_shulker_box","235:0":"minecraft:white_glazed_terracotta","236:0":"minecraft:orange_glazed_terracotta","237:0":"minecraft:magenta_glazed_terracotta","238:0":"minecraft:light_blue_glazed_terracotta","239:0":"minecraft:yellow_glazed_terracotta","240:0":"minecraft:lime_glazed_terracotta","241:0":"minecraft:pink_glazed_terracotta","242:0":"minecraft:gray_glazed_terracotta","243:0":"minecraft:light_gray_glazed_terracotta","244:0":"minecraft:cyan_glazed_terracotta","245:0":"minecraft:purple_glazed_terracotta","246:0":"minecraft:blue_glazed_terracotta","247:0":"minecraft:brown_glazed_terracotta","248:0":"minecraft:green_glazed_terracotta","249:0":"minecraft:red_glazed_terracotta","250:0":"minecraft:black_glazed_terracotta","251:0":"minecraft:white_concrete","251:1":"minecraft:orange_concrete","251:2":"minecraft:magenta_concrete","251:3":"minecraft:light_blue_concrete","251:4":"minecraft:yellow_concrete","251:5":"minecraft:lime_concrete","251:6":"minecraft:pink_concrete","251:7":"minecraft:gray_concrete","251:8":"minecraft:light_gray_concrete","251:9":"minecraft:cyan_concrete","251:10":"minecraft:purple_concrete","251:11":"minecraft:blue_concrete","251:12":"minecraft:brown_concrete","251:13":"minecraft:green_concrete","251:14":"minecraft:red_concrete","251:15":"minecraft:black_concrete","252:0":"minecraft:white_concrete_powder","252:1":"minecraft:orange_concrete_powder","252:2":"minecraft:magenta_concrete_powder","252:3":"minecraft:light_blue_concrete_powder","252:4":"minecraft:yellow_concrete_powder","252:5":"minecraft:lime_concrete_powder","252:6":"minecraft:pink_concrete_powder","252:7":"minecraft:gray_concrete_powder","252:8":"minecraft:light_gray_concrete_powder","252:9":"minecraft:cyan_concrete_powder","252:10":"minecraft:purple_concrete_powder","252:11":"minecraft:blue_concrete_powder","252:12":"minecraft:brown_concrete_powder","252:13":"minecraft:green_concrete_powder","252:14":"minecraft:red_concrete_powder","252:15":"minecraft:black_concrete_powder","255:0":"minecraft:structure_block","256:0":"minecraft:iron_shovel","257:0":"minecraft:iron_pickaxe","258:0":"minecraft:iron_axe","259:0":"minecraft:flint_and_steel","260:0":"minecraft:apple","261:0":"minecraft:bow","262:0":"minecraft:arrow","263:0":"minecraft:coal","263:1":"minecraft:charcoal","264:0":"minecraft:diamond","265:0":"minecraft:iron_ingot","266:0":"minecraft:gold_ingot","267:0":"minecraft:iron_sword","268:0":"minecraft:wooden_sword","269:0":"minecraft:wooden_shovel","270:0":"minecraft:wooden_pickaxe","271:0":"minecraft:wooden_axe","272:0":"minecraft:stone_sword","273:0":"minecraft:stone_shovel","274:0":"minecraft:stone_pickaxe","275:0":"minecraft:stone_axe","276:0":"minecraft:diamond_sword","277:0":"minecraft:diamond_shovel","278:0":"minecraft:diamond_pickaxe","279:0":"minecraft:diamond_axe","280:0":"minecraft:stick","281:0":"minecraft:bowl","282:0":"minecraft:mushroom_stew","283:0":"minecraft:golden_sword","284:0":"minecraft:golden_shovel","285:0":"minecraft:golden_pickaxe","286:0":"minecraft:golden_axe","287:0":"minecraft:string","288:0":"minecraft:feather","289:0":"minecraft:gunpowder","290:0":"minecraft:wooden_hoe","291:0":"minecraft:stone_hoe","292:0":"minecraft:iron_hoe","293:0":"minecraft:diamond_hoe","294:0":"minecraft:golden_hoe","295:0":"minecraft:wheat_seeds","296:0":"minecraft:wheat","297:0":"minecraft:bread","298:0":"minecraft:leather_helmet","299:0":"minecraft:leather_chestplate","300:0":"minecraft:leather_leggings","301:0":"minecraft:leather_boots","302:0":"minecraft:chainmail_helmet","303:0":"minecraft:chainmail_chestplate","304:0":"minecraft:chainmail_leggings","305:0":"minecraft:chainmail_boots","306:0":"minecraft:iron_helmet","307:0":"minecraft:iron_chestplate","308:0":"minecraft:iron_leggings","309:0":"minecraft:iron_boots","310:0":"minecraft:diamond_helmet","311:0":"minecraft:diamond_chestplate","312:0":"minecraft:diamond_leggings","313:0":"minecraft:diamond_boots","314:0":"minecraft:golden_helmet","315:0":"minecraft:golden_chestplate","316:0":"minecraft:golden_leggings","317:0":"minecraft:golden_boots","318:0":"minecraft:flint","319:0":"minecraft:porkchop","320:0":"minecraft:cooked_porkchop","321:0":"minecraft:painting","322:0":"minecraft:golden_apple","322:1":"minecraft:enchanted_golden_apple","323:0":"minecraft:sign","324:0":"minecraft:oak_door","325:0":"minecraft:bucket","326:0":"minecraft:water_bucket","327:0":"minecraft:lava_bucket","328:0":"minecraft:minecart","329:0":"minecraft:saddle","330:0":"minecraft:iron_door","331:0":"minecraft:redstone","332:0":"minecraft:snowball","333:0":"minecraft:oak_boat","334:0":"minecraft:leather","335:0":"minecraft:milk_bucket","336:0":"minecraft:brick","337:0":"minecraft:clay_ball","338:0":"minecraft:sugar_cane","339:0":"minecraft:paper","340:0":"minecraft:book","341:0":"minecraft:slime_ball","342:0":"minecraft:chest_minecart","343:0":"minecraft:furnace_minecart","344:0":"minecraft:egg","345:0":"minecraft:compass","346:0":"minecraft:fishing_rod","347:0":"minecraft:clock","348:0":"minecraft:glowstone_dust","349:0":"minecraft:cod","349:1":"minecraft:salmon","349:2":"minecraft:tropical_fish","349:3":"minecraft:pufferfish","350:0":"minecraft:cooked_cod","350:1":"minecraft:cooked_salmon","351:0":"minecraft:ink_sac","351:1":"minecraft:rose_red","351:2":"minecraft:cactus_green","351:3":"minecraft:cocoa_beans","351:4":"minecraft:lapis_lazuli","351:5":"minecraft:purple_dye","351:6":"minecraft:cyan_dye","351:7":"minecraft:light_gray_dye","351:8":"minecraft:gray_dye","351:9":"minecraft:pink_dye","351:10":"minecraft:lime_dye","351:11":"minecraft:dandelion_yellow","351:12":"minecraft:light_blue_dye","351:13":"minecraft:magenta_dye","351:14":"minecraft:orange_dye","351:15":"minecraft:bone_meal","352:0":"minecraft:bone","353:0":"minecraft:sugar","354:0":"minecraft:cake","355:0":"minecraft:white_bed","355:1":"minecraft:orange_bed","355:2":"minecraft:magenta_bed","355:3":"minecraft:light_blue_bed","355:4":"minecraft:yellow_bed","355:5":"minecraft:lime_bed","355:6":"minecraft:pink_bed","355:7":"minecraft:gray_bed","355:8":"minecraft:light_gray_bed","355:9":"minecraft:cyan_bed","355:10":"minecraft:purple_bed","355:11":"minecraft:blue_bed","355:12":"minecraft:brown_bed","355:13":"minecraft:green_bed","355:14":"minecraft:red_bed","355:15":"minecraft:black_bed","356:0":"minecraft:repeater","357:0":"minecraft:cookie","358:0":"minecraft:filled_map","359:0":"minecraft:shears","360:0":"minecraft:melon_slice","361:0":"minecraft:pumpkin_seeds","362:0":"minecraft:melon_seeds","363:0":"minecraft:beef","364:0":"minecraft:cooked_beef","365:0":"minecraft:chicken","366:0":"minecraft:cooked_chicken","367:0":"minecraft:rotten_flesh","368:0":"minecraft:ender_pearl","369:0":"minecraft:blaze_rod","370:0":"minecraft:ghast_tear","371:0":"minecraft:gold_nugget","372:0":"minecraft:nether_wart","373:0":"minecraft:potion","374:0":"minecraft:glass_bottle","375:0":"minecraft:spider_eye","376:0":"minecraft:fermented_spider_eye","377:0":"minecraft:blaze_powder","378:0":"minecraft:magma_cream","379:0":"minecraft:brewing_stand","380:0":"minecraft:cauldron","381:0":"minecraft:ender_eye","382:0":"minecraft:glistering_melon_slice","383:0":"minecraft:pig_spawn_egg","384:0":"minecraft:experience_bottle","385:0":"minecraft:fire_charge","386:0":"minecraft:writable_book","387:0":"minecraft:written_book","388:0":"minecraft:emerald","389:0":"minecraft:item_frame","390:0":"minecraft:flower_pot","391:0":"minecraft:carrot","392:0":"minecraft:potato","393:0":"minecraft:baked_potato","394:0":"minecraft:poisonous_potato","395:0":"minecraft:map","396:0":"minecraft:golden_carrot","397:0":"minecraft:skeleton_skull","397:1":"minecraft:wither_skeleton_skull","397:2":"minecraft:zombie_head","397:3":"minecraft:player_head","397:4":"minecraft:creeper_head","397:5":"minecraft:dragon_head","398:0":"minecraft:carrot_on_a_stick","399:0":"minecraft:nether_star","400:0":"minecraft:pumpkin_pie","401:0":"minecraft:firework_rocket","402:0":"minecraft:firework_star","403:0":"minecraft:enchanted_book","404:0":"minecraft:comparator","405:0":"minecraft:nether_brick","406:0":"minecraft:quartz","407:0":"minecraft:tnt_minecart","408:0":"minecraft:hopper_minecart","409:0":"minecraft:prismarine_shard","410:0":"minecraft:prismarine_crystals","411:0":"minecraft:rabbit","412:0":"minecraft:cooked_rabbit","413:0":"minecraft:rabbit_stew","414:0":"minecraft:rabbit_foot","415:0":"minecraft:rabbit_hide","416:0":"minecraft:armor_stand","417:0":"minecraft:iron_horse_armor","418:0":"minecraft:golden_horse_armor","419:0":"minecraft:diamond_horse_armor","420:0":"minecraft:lead","421:0":"minecraft:name_tag","422:0":"minecraft:command_block_minecart","423:0":"minecraft:mutton","424:0":"minecraft:cooked_mutton","425:0":"minecraft:black_banner","425:1":"minecraft:red_banner","425:2":"minecraft:green_banner","425:3":"minecraft:brown_banner","425:4":"minecraft:blue_banner","425:5":"minecraft:purple_banner","425:6":"minecraft:cyan_banner","425:7":"minecraft:light_gray_banner","425:8":"minecraft:gray_banner","425:9":"minecraft:pink_banner","425:10":"minecraft:lime_banner","425:11":"minecraft:yellow_banner","425:12":"minecraft:light_blue_banner","425:13":"minecraft:magenta_banner","425:14":"minecraft:orange_banner","425:15":"minecraft:white_banner","426:0":"minecraft:end_crystal","427:0":"minecraft:spruce_door","428:0":"minecraft:birch_door","429:0":"minecraft:jungle_door","430:0":"minecraft:acacia_door","431:0":"minecraft:dark_oak_door","432:0":"minecraft:chorus_fruit","433:0":"minecraft:popped_chorus_fruit","434:0":"minecraft:beetroot","435:0":"minecraft:beetroot_seeds","436:0":"minecraft:beetroot_soup","437:0":"minecraft:dragon_breath","438:0":"minecraft:splash_potion","439:0":"minecraft:spectral_arrow","440:0":"minecraft:tipped_arrow","441:0":"minecraft:lingering_potion","442:0":"minecraft:shield","443:0":"minecraft:elytra","444:0":"minecraft:spruce_boat","445:0":"minecraft:birch_boat","446:0":"minecraft:jungle_boat","447:0":"minecraft:acacia_boat","448:0":"minecraft:dark_oak_boat","449:0":"minecraft:totem_of_undying","450:0":"minecraft:shulker_shell","452:0":"minecraft:iron_nugget","453:0":"minecraft:knowledge_book","2256:0":"minecraft:music_disc_13","2257:0":"minecraft:music_disc_cat","2258:0":"minecraft:music_disc_blocks","2259:0":"minecraft:music_disc_chirp","2260:0":"minecraft:music_disc_far","2261:0":"minecraft:music_disc_mall","2262:0":"minecraft:music_disc_mellohi","2263:0":"minecraft:music_disc_stal","2264:0":"minecraft:music_disc_strad","2265:0":"minecraft:music_disc_ward","2266:0":"minecraft:music_disc_11","2267:0":"minecraft:music_disc_wait"}} diff --git a/src/main/resources/defaults/worldedit.properties b/src/main/resources/defaults/worldedit.properties new file mode 100644 index 0000000..2e63f0d --- /dev/null +++ b/src/main/resources/defaults/worldedit.properties @@ -0,0 +1,33 @@ +#Don't put comments; they get removed +default-max-polygon-points=-1 +schematic-save-dir=schematics +super-pickaxe-many-drop-items=true +register-help=true +nav-wand-item=minecraft:compass +profile=false +trace-unflushed-sessions=false +super-pickaxe-drop-items=true +disallowed-blocks=minecraft:oak_sapling,minecraft:jungle_sapling,minecraft:dark_oak_sapling,minecraft:spruce_sapling,minecraft:birch_sapling,minecraft:acacia_sapling,minecraft:black_bed,minecraft:blue_bed,minecraft:brown_bed,minecraft:cyan_bed,minecraft:gray_bed,minecraft:green_bed,minecraft:light_blue_bed,minecraft:light_gray_bed,minecraft:lime_bed,minecraft:magenta_bed,minecraft:orange_bed,minecraft:pink_bed,minecraft:purple_bed,minecraft:red_bed,minecraft:white_bed,minecraft:yellow_bed,minecraft:powered_rail,minecraft:detector_rail,minecraft:grass,minecraft:dead_bush,minecraft:moving_piston,minecraft:piston_head,minecraft:sunflower,minecraft:rose_bush,minecraft:dandelion,minecraft:poppy,minecraft:brown_mushroom,minecraft:red_mushroom,minecraft:tnt,minecraft:torch,minecraft:fire,minecraft:redstone_wire,minecraft:wheat,minecraft:potatoes,minecraft:carrots,minecraft:melon_stem,minecraft:pumpkin_stem,minecraft:beetroots,minecraft:rail,minecraft:lever,minecraft:redstone_torch,minecraft:redstone_wall_torch,minecraft:repeater,minecraft:comparator,minecraft:stone_button,minecraft:birch_button,minecraft:acacia_button,minecraft:dark_oak_button,minecraft:jungle_button,minecraft:oak_button,minecraft:spruce_button,minecraft:cactus,minecraft:sugar_cane,minecraft:bedrock +max-super-pickaxe-size=5 +max-brush-radius=10 +craftscript-dir=craftscripts +wand-item=minecraft:wooden_axe +shell-save-type= +scripting-timeout=3000 +snapshots-dir= +use-inventory-creative-override=false +log-file=worldedit.log +log-format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s]: %5$s%6$s%n +max-changed-blocks=-1 +default-vertical-height=256 +nav-wand-distance=50 +butcher-default-radius=-1 +default-max-changed-blocks=-1 +history-size=15 +use-inventory=false +allow-symbolic-links=false +use-inventory-override=false +log-commands=false +butcher-max-radius=-1 +max-polygon-points=20 +max-radius=-1 diff --git a/src/main/resources/lang/strings.json b/src/main/resources/lang/strings.json new file mode 100644 index 0000000..e1f7e21 --- /dev/null +++ b/src/main/resources/lang/strings.json @@ -0,0 +1,450 @@ +{ + "worldedit.expand.description.vert": "Vertically expand the selection to world limits.", + "worldedit.expand.expanded": "Region expanded {0} blocks", + "worldedit.expand.expanded.vert": "Region expanded {0} blocks (top-to-bottom).", + + "worldedit.biomeinfo.lineofsight": "Biomes at line of sight point: {0}", + "worldedit.biomeinfo.position": "Biomes at your position: {0}", + "worldedit.biomeinfo.selection": "Biomes in your selection: {0}", + "worldedit.biomeinfo.not-locatable": "Command sender must be present in the world to use the -p flag.", + + "worldedit.brush.radius-too-large": "Maximum allowed brush radius: {0}", + "worldedit.brush.apply.description": "Apply brush, apply a function to every block", + "worldedit.brush.apply.radius": "The size of the brush", + "worldedit.brush.apply.shape": "The shape of the region", + "worldedit.brush.apply.type": "Type of brush to use", + "worldedit.brush.apply.item.warning": "This brush simulates item usages. Its effects may not work on all platforms, may not be undo-able, and may cause strange interactions with other mods/plugins. Use at your own risk.", + "worldedit.brush.paint.description": "Paint brush, apply a function to a surface", + "worldedit.brush.paint.size": "The size of the brush", + "worldedit.brush.paint.shape": "The shape of the region", + "worldedit.brush.paint.density": "The density of the brush", + "worldedit.brush.paint.type": "Type of brush to use", + "worldedit.brush.paint.item.warning": "This brush simulates item usages. Its effects may not work on all platforms, may not be undo-able, and may cause strange interactions with other mods/plugins. Use at your own risk.", + "worldedit.brush.sphere.equip": "Sphere brush shape equipped ({0}).", + "worldedit.brush.cylinder.equip": "Cylinder brush shape equipped ({0} by {1}).", + "worldedit.brush.clipboard.equip": "Clipboard brush shape equipped.", + "worldedit.brush.smooth.equip": "Smooth brush equipped ({0} x {1}x using {2}).", + "worldedit.brush.extinguish.equip": "Extinguisher equipped ({0}).", + "worldedit.brush.gravity.equip": "Gravity brush equipped ({0}).", + "worldedit.brush.butcher.equip": "Butcher brush equipped ({0}).", + "worldedit.brush.operation.equip": "Set brush to {0}.", + "worldedit.brush.heightmap.equip": "Heightmap brush equipped ({0}).", + "worldedit.brush.heightmap.unknown": "Unknown heightmap brush: {0}.", + "worldedit.brush.none.equip": "Brush unbound from your current item.", + + "worldedit.setbiome.changed": "Biomes were changed for approximately {0} blocks.", + "worldedit.setbiome.warning": "You may have to re-join your game (or close and re-open your world) to see changes.", + "worldedit.setbiome.not-locatable": "Command sender must be present in the world to use the -p flag.", + + "worldedit.drawsel.disabled": "Server CUI disabled.", + "worldedit.drawsel.enabled": "Server CUI enabled. This only supports cuboid regions, with a maximum size of {0}x{1}x{2}.", + "worldedit.drawsel.disabled.already": "Server CUI already disabled.", + "worldedit.drawsel.enabled.already": "Server CUI already enabled.", + "worldedit.limit.too-high": "Your maximum allowable limit is {0}.", + "worldedit.limit.set": "Block change limit set to {0}.", + "worldedit.limit.return-to-default": "(Use //limit to go back to the default.)", + "worldedit.timeout.too-high": "Your maximum allowable timeout is {0}ms.", + "worldedit.timeout.set": "Timeout time set to {0}ms.", + "worldedit.timeout.return-to-default": " (Use //timeout to go back to the default.)", + "worldedit.fast.disabled": "Fast mode disabled.", + "worldedit.fast.enabled": "Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes.", + "worldedit.fast.disabled.already": "Fast mode already disabled.", + "worldedit.fast.enabled.already": "Fast mode already enabled.", + "worldedit.perf.sideeffect.set": "Side effect \"{0}\" set to {1}", + "worldedit.perf.sideeffect.get": "Side effect \"{0}\" is set to {1}", + "worldedit.perf.sideeffect.already-set": "Side effect \"{0}\" is already {1}", + "worldedit.perf.sideeffect.set-all": "All side effects set to {0}", + "worldedit.reorder.current": "The reorder mode is {0}", + "worldedit.reorder.set": "The reorder mode is now {0}", + "worldedit.gmask.disabled": "Global mask disabled.", + "worldedit.gmask.set": "Global mask set.", + "worldedit.toggleplace.pos1": "Now placing at pos #1.", + "worldedit.toggleplace.player": "Now placing at the block you stand in.", + "worldedit.toggleplace.not-locatable": "Cannot toggle placing in this context.", + "worldedit.searchitem.too-short": "Enter a longer search string (len > 2).", + "worldedit.searchitem.either-b-or-i": "You cannot use both the 'b' and 'i' flags simultaneously.", + "worldedit.searchitem.searching": "(Please wait... searching items.)", + "worldedit.watchdog.no-hook": "This platform has no watchdog hook.", + "worldedit.watchdog.active.already": "Watchdog hook already active.", + "worldedit.watchdog.inactive.already": "Watchdog hook already inactive.", + "worldedit.watchdog.active": "Watchdog hook now active.", + "worldedit.watchdog.inactive": "Watchdog hook now inactive.", + "worldedit.world.remove": "Removed world override.", + "worldedit.world.set": "Set the world override to {0}. (Use //world to go back to default)", + + "worldedit.undo.undone": "Undid {0} available edits.", + "worldedit.undo.none": "Nothing left to undo.", + "worldedit.redo.redone": "Redid {0} available edits.", + "worldedit.redo.none": "Nothing left to redo.", + "worldedit.clearhistory.cleared": "History cleared.", + + "worldedit.raytrace.noblock": "No block in sight!", + "worldedit.raytrace.require-player": "Raytracing commands require a player!", + + "worldedit.restore.not-configured": "Snapshot/backup restore is not configured.", + "worldedit.restore.not-available": "That snapshot does not exist or is not available.", + "worldedit.restore.failed": "Failed to load snapshot: {0}", + "worldedit.restore.loaded": "Snapshot '{0}' loaded; now restoring...", + "worldedit.restore.restored": "Restored; {0} missing chunks and {1} other errors.", + "worldedit.restore.none-for-specific-world": "No snapshots were found for world '{0}'.", + "worldedit.restore.none-for-world": "No snapshots were found for this world.", + "worldedit.restore.none-found": "No snapshots were found.", + "worldedit.restore.none-found-console": "No snapshots were found. See console for details.", + "worldedit.restore.chunk-not-present": "Chunks were not present in snapshot.", + "worldedit.restore.chunk-load-failed": "No chunks could be loaded. (Bad archive?)", + "worldedit.restore.block-place-failed": "Errors prevented any blocks from being restored.", + "worldedit.restore.block-place-error": "Last error: {0}", + + "worldedit.snapshot.use.newest": "Now using newest snapshot.", + "worldedit.snapshot.use": "Snapshot set to: {0}", + "worldedit.snapshot.none-before": "Couldn't find a snapshot before {0}.", + "worldedit.snapshot.none-after": "Couldn't find a snapshot after {0}.", + "worldedit.snapshot.index-above-0": "Invalid index, must be greater than or equal to 1.", + "worldedit.snapshot.index-oob": "Invalid index, must be between 1 and {0}.", + + "worldedit.schematic.unknown-format": "Unknown schematic format: {0}.", + "worldedit.schematic.load.does-not-exist": "Schematic {0} does not exist!", + "worldedit.schematic.load.loading": "(Please wait... loading schematic.)", + "worldedit.schematic.load.still-loading": "(Please wait... still loading schematic.)", + "worldedit.schematic.save.already-exists": "That schematic already exists. Use the -f flag to overwrite it.", + "worldedit.schematic.save.failed-directory": "Could not create folder for schematics!", + "worldedit.schematic.save.saving": "(Please wait... saving schematic.)", + "worldedit.schematic.save.still-saving": "(Please wait... still saving schematic.)", + "worldedit.schematic.delete.does-not-exist": "Schematic {0} does not exist!", + "worldedit.schematic.delete.failed": "Deletion of {0} failed! Is it read-only?", + "worldedit.schematic.delete.deleted": "{0} has been deleted.", + "worldedit.schematic.formats.title": "Available clipboard formats (Name: Lookup names)", + "worldedit.schematic.unsupported-minecraft-version": "This version of WorldEdit does not support your Minecraft version. Schematics will not work until this is resolved.", + + "worldedit.pos.already-set": "Position already set.", + "worldedit.pos.console-require-coords": "You must provide coordinates as console.", + "worldedit.hpos.no-block": "No block in sight!", + "worldedit.hpos.already-set": "Position already set.", + "worldedit.chunk.selected-multiple": "Chunks selected: ({0}, {1}, {2}) - ({3}, {4}, {5})", + "worldedit.chunk.selected": "Chunk selected: {0}, {1}, {2}", + "worldedit.wand.invalid": "Wand item is mis-configured or disabled.", + "worldedit.wand.selwand.info": "Left click: select pos #1; Right click: select pos #2", + "worldedit.wand.navwand.info": "Left click: jump to location; Right click: pass through walls", + "worldedit.wand.selwand.now.tool": "The selection wand is now a normal tool. You can disable it with {0} and rebind it to any item with {1} or get a new wand with {2}.", + "worldedit.contract.contracted": "Region contracted {0} blocks.", + "worldedit.shift.shifted": "Region shifted.", + "worldedit.outset.outset": "Region outset.", + "worldedit.inset.inset": "Region inset.", + "worldedit.size.offset": "Offset: {0}", + "worldedit.size.type": "Type: {0}", + "worldedit.size.size": "Size: {0}", + "worldedit.size.distance": "Cuboid distance: {0}", + "worldedit.size.blocks": "# of blocks: {0}", + "worldedit.count.counted": "Counted: {0}", + "worldedit.distr.no-blocks": "No blocks counted.", + "worldedit.distr.no-previous": "No previous distribution.", + "worldedit.distr.total": "Total Block Count: {0}", + "worldedit.select.cleared": "Selection cleared.", + "worldedit.select.cuboid.message": "Cuboid: left click for point 1, right click for point 2", + "worldedit.select.cuboid.description": "Select two corners of a cuboid", + "worldedit.select.extend.message": "Cuboid: left click for a starting point, right click to extend", + "worldedit.select.extend.description": "Fast cuboid selection mode", + "worldedit.select.poly.message": "2D polygon selector: Left/right click to add a point.", + "worldedit.select.poly.limit-message": "{0} points maximum.", + "worldedit.select.poly.description": "Select a 2D polygon with height", + "worldedit.select.ellipsoid.message": "Ellipsoid selector: left click=center, right click to extend", + "worldedit.select.ellipsoid.description": "Select an ellipsoid", + "worldedit.select.sphere.message": "Sphere selector: left click=center, right click to set radius", + "worldedit.select.sphere.description": "Select a sphere", + "worldedit.select.cyl.message": "Cylindrical selector: Left click=center, right click to extend", + "worldedit.select.cyl.description": "Select a cylinder", + "worldedit.select.convex.message": "Convex polyhedral selector: Left click=First vertex, right click to add more.", + "worldedit.select.convex.limit-message": "{0} points maximum.", + "worldedit.select.convex.description": "Select a convex polyhedral", + "worldedit.select.default-set": "Your default region selector is now {0}.", + + "worldedit.chunkinfo.chunk": "Chunk: {0}, {1}", + "worldedit.chunkinfo.old-filename": "Old format: {0}", + "worldedit.chunkinfo.mcregion-filename": "McRegion: region/{0}", + "worldedit.listchunks.listfor": "Listing chunks for: {0}", + + "worldedit.drain.drained": "{0} blocks have been drained.", + "worldedit.fill.created": "{0} blocks have been filled.", + "worldedit.fillr.created": "{0} blocks have been filled.", + "worldedit.fixlava.fixed": "{0} blocks have been fixed.", + "worldedit.fixwater.fixed": "{0} blocks have been fixed.", + "worldedit.removeabove.removed": "{0} blocks have been removed.", + "worldedit.removebelow.removed": "{0} blocks have been removed.", + "worldedit.removenear.removed": "{0} blocks have been removed.", + "worldedit.replacenear.replaced": "{0} blocks have been replaced.", + "worldedit.snow.created": "{0} surfaces have been covered.", + "worldedit.thaw.removed": "{0} blocks have been thawed.", + "worldedit.green.changed": "{0} blocks have been greened.", + "worldedit.extinguish.removed": "{0} fires have been extinguished.", + "worldedit.butcher.killed": "{0} mobs have been killed in a radius of {1}.", + "worldedit.butcher.explain-all": "Use -1 to remove all mobs in loaded chunks", + "worldedit.remove.removed": "{0} entities have been marked for removal.", + "worldedit.remove.explain-all": "Use -1 to remove all entities in loaded chunks", + "worldedit.calc.invalid": "'{0}' could not be parsed as a valid expression", + "worldedit.calc.invalid.with-error": "'{0}' could not be parsed as a valid expression: '{1}'", + + "worldedit.paste.pasted": "The clipboard has been pasted at {0}", + "worldedit.paste.selected": "Selected clipboard paste region.", + "worldedit.rotate.no-interpolation": "Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended.", + "worldedit.rotate.rotated": "The clipboard copy has been rotated.", + "worldedit.flip.flipped": "The clipboard copy has been flipped.", + "worldedit.clearclipboard.cleared": "Clipboard cleared.", + + "worldedit.set.done": "Operation completed.", + "worldedit.set.done.verbose": "Operation completed ({0}).", + "worldedit.line.changed": "{0} blocks have been changed.", + "worldedit.line.invalid-type": "//line only works with cuboid selections or convex polyhedral selections", + "worldedit.curve.changed": "{0} blocks have been changed.", + "worldedit.curve.invalid-type": "//curve only works with convex polyhedral selections", + "worldedit.replace.replaced": "{0} blocks have been replaced.", + "worldedit.stack.changed": "{0} blocks changed. Undo with //undo", + "worldedit.stack.intersecting-region": "Stack offset must not collide with the region when using block units", + "worldedit.regen.regenerated": "Region regenerated.", + "worldedit.regen.failed": "Unable to regenerate chunks. Check console for details.", + "worldedit.walls.changed": "{0} blocks have been changed.", + "worldedit.faces.changed": "{0} blocks have been changed.", + "worldedit.overlay.overlaid": "{0} blocks have been overlaid.", + "worldedit.naturalize.naturalized": "{0} block(s) have been made to look more natural.", + "worldedit.center.changed": "Center set. ({0} blocks changed)", + "worldedit.smooth.changed": "Terrain's height map smoothed. {0} blocks changed.", + "worldedit.move.moved": "{0} blocks moved.", + "worldedit.deform.deformed": "{0} blocks have been deformed.", + "worldedit.hollow.changed": "{0} blocks have been changed.", + "worldedit.forest.created": "{0} trees created.", + "worldedit.flora.created": "{0} flora created.", + + "worldedit.unstuck.moved": "There you go!", + "worldedit.ascend.obstructed": "No free spot above you found.", + "worldedit.ascend.moved": "Ascended {0} levels.", + "worldedit.descend.obstructed": "No free spot below you found.", + "worldedit.descend.moved": "Descended {0} levels.", + "worldedit.ceil.obstructed": "No free spot above you found.", + "worldedit.ceil.moved": "Woosh!", + "worldedit.thru.obstructed": "No free spot ahead of you found.", + "worldedit.thru.moved": "Woosh!", + "worldedit.jumpto.moved": "Poof!", + "worldedit.jumpto.none": "No block in sight (or too far away)!", + "worldedit.up.obstructed": "You would hit something above you.", + "worldedit.up.moved": "Woosh!", + + "worldedit.cyl.invalid-radius": "You must either specify 1 or 2 radius values.", + "worldedit.cyl.created": "{0} blocks have been created.", + "worldedit.sphere.invalid-radius": "You must either specify 1 or 3 radius values.", + "worldedit.sphere.created": "{0} blocks have been created.", + "worldedit.forestgen.created": "{0} trees created.", + "worldedit.pumpkins.created": "{0} pumpkin patches created.", + "worldedit.pyramid.created": "{0} blocks have been created.", + "worldedit.generate.created": "{0} blocks have been created.", + "worldedit.generatebiome.changed": "{0} biomes affected.", + + "worldedit.reload.config": "Configuration reloaded!", + "worldedit.report.written": "WorldEdit report written to {0}", + "worldedit.report.error": "Failed to write report: {0}", + "worldedit.report.callback": "WorldEdit report: {0}.report", + "worldedit.timezone.invalid": "Invalid timezone", + "worldedit.timezone.set": "Timezone set for this session to: {0}", + "worldedit.timezone.current": "The current time in that timezone is: {0}", + "worldedit.version.version": "WorldEdit version {0}", + + "worldedit.trace.no-tracing-extents": "Trace: No extent was used.", + "worldedit.trace.action-failed": "Trace: Action(s) {0} at {1} discarded by extent {2}", + "worldedit.trace.active.already": "Trace mode already active.", + "worldedit.trace.inactive.already": "Trace mode already inactive.", + "worldedit.trace.active": "Trace mode now active.", + "worldedit.trace.inactive": "Trace mode now inactive.", + + "worldedit.command.time-elapsed": "{0}s elapsed (history: {1} changed; {2} blocks/sec).", + "worldedit.command.permissions": "You are not permitted to do that. Are you in the right mode?", + "worldedit.command.player-only": "This command must be used with a player.", + "worldedit.command.error.report": "Please report this error: [See console]", + "worldedit.pastebin.uploading": "(Please wait... sending output to pastebin...)", + "worldedit.session.cant-find-session": "Unable to find session for {0}", + "worldedit.platform.no-file-dialog": "File dialogs are not supported in your environment.", + + "worldedit.asset.load.loading": "(Please wait... loading asset.)", + "worldedit.asset.load.still-loading": "(Please wait... still loading asset.)", + "worldedit.asset.load.failed": "Failed to load asset", + + "worldedit.tool.max-block-changes": "Max blocks change limit reached.", + "worldedit.tool.no-block": "No block in sight!", + "worldedit.tool.repl.equip": "Block replacer tool bound to {0}.", + "worldedit.tool.repl.switched": "Replacer tool switched to: {0}", + "worldedit.tool.data-cycler.equip": "Block data cycler tool bound to {0}.", + "worldedit.tool.data-cycler.block-not-permitted": "You are not permitted to cycle the data value of that block.", + "worldedit.tool.data-cycler.cant-cycle": "That block's data cannot be cycled!", + "worldedit.tool.data-cycler.new-value": "Value of {0} is now {1}.", + "worldedit.tool.data-cycler.cycling": "Now cycling {0}.", + "worldedit.tool.deltree.equip": "Floating tree remover tool bound to {0}.", + "worldedit.tool.deltree.not-tree": "That's not a tree.", + "worldedit.tool.deltree.not-floating": "That's not a floating tree.", + "worldedit.tool.tree.equip": "Tree tool bound to {0}.", + "worldedit.tool.tree.obstructed": "A tree can't go there.", + "worldedit.tool.info.equip": "Info tool bound to {0}.", + "worldedit.tool.info.blockstate.hover": "Block state", + "worldedit.tool.info.internalid.hover": "Internal ID", + "worldedit.tool.info.legacy.hover": "Legacy id:data", + "worldedit.tool.info.light.hover": "Block Light/Light Above", + "worldedit.tool.none.equip": "Tool unbound from your current item.", + "worldedit.tool.none.to.unequip": "Your current item is not bound.", + "worldedit.tool.selwand.equip": "Selection wand bound to {0}.", + "worldedit.tool.navwand.equip": "Navigation wand bound to {0}.", + "worldedit.tool.floodfill.equip": "Block flood fill tool bound to {0}.", + "worldedit.tool.farwand.equip": "Far wand tool bound to {0}.", + "worldedit.tool.lrbuild.equip": "Long-range building tool bound to {0}.", + "worldedit.tool.lrbuild.set": "Left-click set to {0}; right-click set to {1}.", + "worldedit.tool.stack.equip": "Stack tool bound to {0}.", + + "worldedit.tool.unbind-instruction": "Run {0} while holding the item to unbind it.", + + "worldedit.tool.superpickaxe.mode.single": "Mode is now single. Left click with a pickaxe. // to disable.", + "worldedit.tool.superpickaxe.mode.area": "Mode is now area. Left click with a pickaxe. // to disable.", + "worldedit.tool.superpickaxe.mode.recursive": "Mode is now recursive. Left click with a pickaxe. // to disable.", + "worldedit.tool.superpickaxe.max-range": "Maximum range is {0}.", + "worldedit.tool.superpickaxe.enabled.already": "Super pickaxe already enabled.", + "worldedit.tool.superpickaxe.disabled.already": "Super pickaxe already disabled.", + "worldedit.tool.superpickaxe.enabled": "Super pickaxe enabled.", + "worldedit.tool.superpickaxe.disabled": "Super pickaxe disabled.", + "worldedit.tool.mask.set": "Brush mask set.", + "worldedit.tool.mask.disabled": "Brush mask disabled.", + "worldedit.tool.material.set": "Brush material set.", + "worldedit.tool.range.set": "Brush range set.", + "worldedit.tool.size.set": "Brush size set.", + "worldedit.tool.tracemask.set": "Trace mask set.", + "worldedit.tool.tracemask.disabled": "Trace mask disabled.", + "worldedit.tool.error.cannot-bind": "Can't bind tool to {0}: {1}", + "worldedit.tool.error.item-only": "Blocks can't be used.", + + "worldedit.execute.script-permissions": "You don't have permission to use that script.", + "worldedit.executelast.no-script": "Use /cs with a script name first.", + "worldedit.script.read-error": "Script read error: {0}", + "worldedit.script.unsupported": "Only .js scripts are currently supported", + "worldedit.script.file-not-found": "Script does not exist: {0}", + "worldedit.script.no-script-engine": "Failed to find an installed script engine.\nPlease see https://worldedit.enginehub.org/en/latest/usage/other/craftscripts/", + "worldedit.script.failed": "Failed to execute: {0}", + "worldedit.script.failed-console": "Failed to execute (see console): {0}", + + "worldedit.operation.affected.biome": "{0} biomes affected", + "worldedit.operation.affected.block": "{0} blocks affected", + "worldedit.operation.affected.column": "{0} columns affected", + "worldedit.operation.affected.entity": "{0} entities affected", + "worldedit.operation.deform.expression": "deformed using {0}", + + "worldedit.error.invalid-number": "Number expected; string given.", + "worldedit.error.invalid-number.matches": "Number expected; string \"{0}\" given.", + "worldedit.error.incomplete-region": "Make a region selection first.", + "worldedit.error.unknown-block": "Block name '{0}' was not recognized.", + "worldedit.error.unknown-entity": "Entity name '{0}' was not recognized.", + "worldedit.error.unknown-mob": "Mob name '{0}' was not recognized.", + "worldedit.error.unknown-biome": "Biome name '{0}' was not recognized.", + "worldedit.error.unknown-tag": "Tag name '{0}' was not recognized.", + "worldedit.error.empty-tag": "Tag name '{0}' has no contents.", + "worldedit.error.no-match": "No match for '{0}'.", + "worldedit.error.disallowed-block": "Block '{0}' not allowed (see WorldEdit configuration).", + "worldedit.error.max-changes": "Max blocks changed in an operation reached ({0}).", + "worldedit.error.max-brush-radius": "Maximum brush radius (in configuration): {0}", + "worldedit.error.max-radius": "Maximum radius (in configuration): {0}", + "worldedit.error.unknown-direction": "Unknown direction: {0}", + "worldedit.error.empty-clipboard": "Your clipboard is empty. Use //copy first.", + "worldedit.error.invalid-filename": "Filename '{0}' invalid: {1}", + "worldedit.error.invalid-filename.invalid-characters": "Invalid characters or extension missing", + "worldedit.error.file-resolution": "File '{0}' resolution error: {1}", + "worldedit.error.file-resolution.outside-root": "Path is outside allowable root", + "worldedit.error.file-resolution.resolve-failed": "Failed to resolve path", + "worldedit.error.file-aborted": "File selection aborted.", + "worldedit.error.no-file-selected": "No file selected.", + "worldedit.error.world-unloaded": "The world was unloaded already.", + "worldedit.error.not-a-block": "This item is not a block.", + "worldedit.error.not-a-block.item": "The item '{0}' is not a block.", + "worldedit.error.incorrect-usage": "Usage: {0}", + "worldedit.error.invalid-page": "Invalid page number", + "worldedit.error.parser.bad-state-format": "Bad state format in {0}", + "worldedit.error.parser.duplicate-property": "Duplicate property: {0}", + "worldedit.error.parser.empty-state": "Empty part in state", + "worldedit.error.parser.missing-equals-separator": "Missing '=' separator", + "worldedit.error.parser.clipboard.missing-offset": "Offset specified with @ but no offset given. Use '#copy@[x,y,z]'.", + "worldedit.error.parser.unknown-property": "Unknown property '{0}' for block '{1}'", + "worldedit.error.parser.unknown-value": "Unknown value '{0}' for property '{1}'", + "worldedit.error.parser.empty-property": "Empty property in state", + "worldedit.error.parser.empty-value": "Empty value in state", + "worldedit.error.parser.invalid-colon": "Invalid colon.", + "worldedit.error.parser.invalid-expression": "Invalid expression: {0}", + "worldedit.error.parser.negate-nothing": "Cannot negate nothing!", + "worldedit.error.parser.hanging-lbracket": "Invalid format. Hanging bracket at '{0}'.", + "worldedit.error.parser.missing-rbracket": "State is missing trailing ']'", + "worldedit.error.parser.missing-random-type": "Missing the type after the % symbol for '{0}'", + "worldedit.error.parser.clipboard.missing-coordinates": "Clipboard offset needs x,y,z coordinates.", + "worldedit.error.parser.player-only": "Input '{0}' requires a player!", + "worldedit.error.disabled": "This functionality is disabled (see WorldEdit configuration).", + "worldedit.error.unknown": "Unknown error occurred: {0}", + "worldedit.error.missing-extent": "No Extent is known", + "worldedit.error.missing-session": "No LocalSession is known", + "worldedit.error.missing-world": "You need to provide a world (Try //world)", + "worldedit.error.missing-actor": "No actor is known", + + "worldedit.selection.convex.info.vertices": "Vertices: {0}", + "worldedit.selection.convex.info.triangles": "Triangles: {0}", + "worldedit.selection.convex.explain.primary": "Started new selection with vertex {0}.", + "worldedit.selection.convex.explain.secondary": "Added vertex {0} to the selection.", + "worldedit.selection.cuboid.info.pos1": "Position 1: {0}", + "worldedit.selection.cuboid.info.pos2": "Position 2: {0}", + "worldedit.selection.cuboid.explain.primary": "First position set to {0}.", + "worldedit.selection.cuboid.explain.primary-area": "First position set to {0} ({1}).", + "worldedit.selection.cuboid.explain.secondary": "Second position set to {0}.", + "worldedit.selection.cuboid.explain.secondary-area": "Second position set to {0} ({1}).", + "worldedit.selection.extend.explain.primary": "Started selection at {0} ({1}).", + "worldedit.selection.extend.explain.secondary": "Extended selection to encompass {0} ({1}).", + "worldedit.selection.ellipsoid.info.center": "Center: {0}", + "worldedit.selection.ellipsoid.info.radius": "X/Y/Z Radius: {0}", + "worldedit.selection.ellipsoid.explain.primary": "Center position set to {0}.", + "worldedit.selection.ellipsoid.explain.primary-area": "Center position set to {0} ({1}).", + "worldedit.selection.ellipsoid.explain.secondary": "Radius set to {0}.", + "worldedit.selection.ellipsoid.explain.secondary-area": "Radius set to {0} ({1}).", + "worldedit.selection.ellipsoid.error.even-horizontal": "Ellipsoid changes must be even for each dimension.", + "worldedit.selection.cylinder.info.center": "Center: {0}", + "worldedit.selection.cylinder.info.radius": "Radius: {0}", + "worldedit.selection.cylinder.explain.primary": "Starting a new cylindrical selection at {0}.", + "worldedit.selection.cylinder.explain.secondary": "Radius set to {0}/{1} blocks. ({2})", + "worldedit.selection.cylinder.explain.secondary-missing": "You must select the center point before setting the radius.", + "worldedit.selection.cylinder.error.even-horizontal": "Cylinders changes must be even for each horizontal dimension.", + "worldedit.selection.polygon2d.info": "# points: {0}", + "worldedit.selection.polygon2d.explain.primary": "Starting a new polygon at {0}.", + "worldedit.selection.polygon2d.explain.secondary": "Added point #{0} at {1}.", + "worldedit.selection.polygon2d.error.expand-only-vertical": "Polygons can only be expanded vertically.", + "worldedit.selection.polygon2d.error.contract-only-vertical": "Polygons can only be contracted vertically.", + "worldedit.selection.sphere.explain.secondary": "Radius set to {0}.", + "worldedit.selection.sphere.explain.secondary-defined": "Radius set to {0} ({1}).", + "worldedit.selection.null.error.immutable": "Cannot change NullRegion.", + "worldedit.selection.intersection.error.cannot-expand": "Cannot expand a region intersection.", + "worldedit.selection.intersection.error.cannot-contract": "Cannot contract a region intersection.", + "worldedit.selection.transform.error.cannot-expand": "Cannot expand a TransformedRegion.", + "worldedit.selection.transform.error.cannot-contract": "Cannot contract a TransformedRegion.", + "worldedit.selection.transform.error.cannot-change": "Cannot change a TransformedRegion.", + + "worldedit.sideeffect.lighting": "Lighting", + "worldedit.sideeffect.lighting.description": "Updates block lighting", + "worldedit.sideeffect.neighbors": "Neighbors", + "worldedit.sideeffect.neighbors.description": "Notifies nearby blocks of changes", + "worldedit.sideeffect.update": "Update", + "worldedit.sideeffect.update.description": "Notifies the changed block", + "worldedit.sideeffect.validation": "Validation", + "worldedit.sideeffect.validation.description": "Validates and fixes inconsistent world state, such as disconnected blocks", + "worldedit.sideeffect.entity_ai": "Entity AI", + "worldedit.sideeffect.entity_ai.description": "Updates Entity AI paths for the block changes", + "worldedit.sideeffect.events": "Mod/Plugin Events", + "worldedit.sideeffect.events.description": "Tells other mods/plugins about these changes when applicable", + "worldedit.sideeffect.state.on": "On", + "worldedit.sideeffect.state.delayed": "Delayed", + "worldedit.sideeffect.state.off": "Off", + "worldedit.sideeffect.box.current": "Current", + "worldedit.sideeffect.box.change-to": "Click to set to {0}", + + "worldedit.help.command-not-found": "The command '{0}' could not be found.", + "worldedit.help.no-subcommands": "'{0}' has no sub-commands. (Maybe '{1}' is for a parameter?)", + "worldedit.help.subcommand-not-found": "The sub-command '{0}' under '{1}' could not be found.", + + "worldedit.cli.stopping": "Stopping!", + "worldedit.cli.unknown-command": "Unknown command!", + + "worldedit.version.bukkit.unsupported-adapter": "This WorldEdit version does not fully support your version of Bukkit. Block entities (e.g. chests) will be empty, block properties (e.g. rotation) will be missing, and other things may not work. Update WorldEdit to restore this functionality:\n{0}", + "worldedit.bukkit.no-edit-without-adapter": "Editing on unsupported versions is disabled." +} diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index 59c5240..0a39f61 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,8 +1,6 @@ { - "pack": { - "description": { - "text": "${mod_id} resources" - }, - "pack_format": ${pack_format_number} - } -} + "pack": { + "description": "WorldEdit Resources", + "pack_format": 8 + } +} \ No newline at end of file diff --git a/src/main/resources/worldedit-forge.mixins.json b/src/main/resources/worldedit-forge.mixins.json new file mode 100644 index 0000000..d7de4e1 --- /dev/null +++ b/src/main/resources/worldedit-forge.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "package": "com.sk89q.worldedit.forge.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "AccessorServerPlayerGameMode", + "MixinLevelChunkSetBlockHook", + "MixinServerGamePacketListenerImpl" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "worldedit-forge.mixins.refmap.json" +} diff --git a/src/main/resources/worldedit-icon.png b/src/main/resources/worldedit-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..dc269dcf7b17ffb3d5b4ba950c2dda74a3b5c26b GIT binary patch literal 5636 zcmV+f7W?UmP)3LSnB__s;iHVxjB^FVQ(UfOILyRbTLPRu*MnpA= zz;UXFQ4mp1Jz}CRiAg9mR!a3wtBj{9qnfB-1O?fDv+V3l_xHVY&wS0R?yqO3cNSo# z+|PQ|-K=?+We4X@XyYK&%M9^1Mtwp8I1He-VXkP#jo@_;c z-${boY{U=7XDqN#-++JzpU3@d_YU%;z?U{O;3!J^hD)?kAWp^-Ck&qDR8NjTfQtcW z5dhrei31HZM5DnNaMf9Tj`|e>Ocnqj&=+JW|5+OVF3dUV=LFEyNI>jHgVFD(RThFJ zu&fz~Y}u$J=m`aybW(3o{(MZ6bsBn?qZ+akWl*Yb^cU4C;ln7Yw$=tuuq^tTe`X6M>;%oo zIUWpzZ1C12!|>0;gES%r;|W1t(p*JyLVJ_-!+JJfqV64dvE;zB0(}_lGX!c)fry|M ztw|R6f+dheNz;1^vaTJysC%CQ+DvKVBuJkVJ9DfggzR6a49HQQPbm(|r;GwA_&&pt zzL~NxWTJQ=G7Jp;2P`}j3u#k9mVCnKhUbp^v= z7?>~(L{&&(%r$FH*{AdrwWA*e!e+{cfv90%<%dtC&nX0j!Nfz-niichYba8k*jsk= zqb92${h&{-4Z(=`2BI<~3J?&oO$xyygoTib2x(vKk!){NdVj4V%M z`7LJ{IY_*w%9qVzy} zfC3OE5KWgDvIbLmI#5*V#GV4&?Lj%afq^9V8NQhkJ2ZoxE>ZZQ;h6EV<@oQY^k>9nih0uYuU1lp`h zSIA^^vb5c{SVMNV&tNlUPH!oI@#&+Tjvp`zWr~=14 zww`d7Jz3cBKnhC7861JL%EmbJ=3`HBt?`qF6*Z?0_@@-?`mw;14?MZ60V8#W z;U@|)NEC+B<2*=fs4QSt2SLQkN3$tCd7CEtdgMYHP%2v_7(U0gm%vELaKlUi%IkhP&xqnSb^-Re+Um+`4HD0NhsP3(W?nQGzZhR}v_r;1uDvHS`WsW?4V9d;)WZ0f27rE^N)xGR;>Ae1O zDu`1EpbG$Q+XFz@XY^{HA<%#kmWXBu&rEe(wVdoJ2UgWmwY?AIhwm3?AeWOLZMKWA z|4|g4U*8P*ft1h?qFEE}i03RG5ktv*{@B5eA1%tDuxj$7&Reev4~7to5?n?9G2p76 z7F*oEJAp8aVmatTs65Dk0c98qR{EMz6^7jMK6Kr10mw}o(g2X=iXs~MFcVDt=ShF& zOZkpVZfQc>u00Mzp^-CuK(cbKyjMThRl5O*>A)dy;55|w7dBI3{0cPOd;O9YvT}xu@24I zRE246*k^RiPv$e+_uqxC>t~fhMgq(R=NfdOl`+se=phl9#|d52k%kWbu$45`r=D0RbBwn zAe1N2+78gxPWFL^^^Uvdt`s)6BnmwH9=Nqo_|ps3sj=_mzGDrD0IpX+7wlw{#g)Du zr`%Ckp_ajKXZbJKrA&u})prMhpJg{o_daSyWt#TTd-VyN3CbbBCYnB!JA6=F1n0rfMXcov?f^53DTui74?vOy10K9!C0pUuY zKn+7n)OjjTM8^b`ojzA(zW8+k!m@@1{gwZf-8at>G?+J7kWpQXZ)9lu-W=I_(m7TP zO_3n3px&Qd=L|gcSd%79RaBC-gu?yC6aXtjxzz=lB(Qqr(N5gniD-#P-xL9bVhd~P zL9*kTyFiQ?#}Jajc=*hH&6bl#t;AtvVu1gccYCC;qvGwHd*Baze&ysoW;0wQR zLP$1H3-=uJU@gW#Q|1%FUKYYk08mMRm`eg&e@$NyXCU7q0tHejHFn-oVi>~`A|ZOm z&b>uzeQhKC&tL3-+6MJ5zt&+G$!oP51Pd}2BH|8wAdm#-N}_HH@UjFz%w=Syl}iAj z#^+EM1@Rl&dg^(uwfEFoGqspG{HRaBo*C44?-D2f^g0bA8Ib@ScTs8>1flpu0cl&Q zp#aQN9u$H2(*(0DhS5`$k0U@f)XonTs(wuw*)r`+3mS0rtzKH(-g#dM2FvgU2EtQc z7Cn>H)O&581It|$Q+l&Yn-=sx7b;B|N*8)*8F&^3bEy4iN#c%{&2+OhqA zmgCNWVEPi&Vwn6gbZ!{e$3a&u+*)uCu|3T=!$RB#S#3Gk0btcLvZ-Oym0NX-7#<^AwV5tJLQrqKn#!$OT+Ggxm#S8QbKd^5)3^M( z3_3+bE-)no5}!LGAMz7|#JGut%;&$79@133_L7rZzR+fEH*HKJ7ZTrDKjc3jjli0H zu}gG}4FLbh;eY%uLret9D#^-{|Mde+%a35M#~R_MOrVjEot1tLeXiJ+J@ z7QpgRH)^Bv<|~6k0V(|d|K+-`o7INW#rQc@LKp!J3`4;x+M>b5n}32&+K5$eA0^I& z(VS_>t(#$}A-lE=P}i0YYlp95pT%$tFlO};SnW~6k(j6!?}COgQs2P~Q4t6k#|Xr= zNx^G`aHy_Y#1S@sLeYvDfe6%(5?0v)7^YaDvKKBW zQgqoik-lciRH4}e7z|i|Pl;CBTB``&4}(Z+==O?<4-9ne%pEw6Q$L8jo^G^hC)F4so1y-@*7qSBdSvpOPwASUkPG=Fv4umauIvo03hPj@PB z2%!zUBI0y>1cV}A2o&fe0ayqNEX0j=d%5|dGmmO!&Q(7{0zn8+k^qibHf5nrOtlZKTut$dBFEvU&M(Xh1v zD>!s}@_sd`nHWDw%6HyK5hD8zG~*>j3`N6uSd_cy$tX~@+M?7)G$7TDCG$l90wcRw zkTC=V6ZB^Y1@C!mAP|2QTmCXr+u%IR)0@=BTX|TiRbHy;G2QU~&1d2e|nse0M zfFwZg#KzO&cvVksvRH;a7vOuFDGAb&kOW86Oos%L=$PQt&_L+NUjo>vvxmHv#zpGXNkl;r_fQH!$y#XU0xT}AMOs&vqaT#uQU%AhU)2Z z-FM!yEwf`X+F;Hw*i2O^;WCs}Eta@k1&%1Zlz;_TcE+fU>B#TVcJ`dX=C7Tch8o89 z&NYBaBE~4Jf{4!`VxN(?$$`z+Vg)oYFKJ#72@Aws@&Ic|JP`45Bv4vUol$7}_BqY9 zz;NGrL*+ZySfT=OMZ_8cuwEdt�v@D{EVq36fj3OY$AQ03_h`Fl*CG)v2XGC^PGR=7O z{$l^i#c2V&AD3yLVqie&B=8xu%U4jf+165lxYgek4iT(jrc#V-Ck8NxjE#~Ra0MX1 zNxCHW_h2+9hq0tdHwv;w#PNt^ZV|vRQ@aibo3H!*qYnjup;TwWRW^mhIWp8iXK-!S zr%Wgmzz9Jm7~vT3U~KncaMy^rQz}qYGZ+RijNJr;p(sV;a;{o79GFT408r!M>~DY+ ztHlp&8bF1n!c-Fw){Hgz{uPUx1+w{!ZCaqHrW1hSGj=BsHedg#04DUiYQ8mbZ<+o6 zoFP-!sr?Tg+kWn)#r}Jjr9iqUfhPy3okubtW`#3#*k|45<48O9^`4fd~G>cI#X z%`nV?nTKJlw>aqAvpYGo+tyWXbKB`L&M0|&0Z(=gh_XJFt!4~8c$MHZ#?yYR;ZJ) z{g?OU`|nxOtQ~j+hN&G~Xad85*9Q=mwVt$jvJx6(%KGUL zhEcB@nBC*arTii5Q8;bhd+W6s)`colTNeL}6NL@13FZ<{HfcDSdIch~?F7;lp`K>M z2nbU%z}F1+84a^5>4TnZ^W;%an(IyqG zVi?@jA`FeecwfU0u>=Nnx24+fm-OI=OWseq4$Y_fD6r z)qf94wXN5cYY8BWm3n-+DVtfu#tax*Zzur6Cd~w3!XTX}WS{Zz`j)ngC4P&DC-ge* zZxmshz;KHv`ciRq6$=rQR2ruOhCmF5L4=kEn3cYd?H5a?1wPZBvc5||vQlatjn!8e z5`ksm^(DN~i_ky?#uXqd`;3nv5SEM(k7sS`Tt%Ri5u6cF1O~)zgkx%xF|DrH=fyr_ z^vj949DFYjpx@vfWWoh6g9z=n7#$cBPO5NK&zu18ZmB+ulMSEovD6R~%Br-5rzn5{ z#SL-Bwy(7f);Ps59yVZ%0x|qWClP&1DGy4}RTBA9Vyc3Lp;cN+2L4!X#k6;hnyktR z$?r*mhlxn=GA`7oyyg+BG(Z3a*W5b=l(5n_sv#^E!XpCU0tKK{c=@mv3SApJS#t`6 zwWGwstn`g)NMa~>msGS(0o@M-%{mhpPC{xFrimhB2{KXbmA+9REWc0$IYM|0h%!D7 zp*tQcG&{3)7;F02OpO8=nXDHCXG?&GfCz(}3O8nB$ekOSQ40ECC&Cy70s?U@5lxT) zw~-HpgFt@H5f~cIdR}^Lj!~yRGAMTdz-$RXQZJ(PMS+&!nmgis7&|}C7}XFK1h`EA ze54etM4;x-N-hnD09+!vLkRpa01PsKQ6RfSY{Ulz!gGU)W-EXbkl+A~WTS7Qi0F13 e@il_R8-E89rZjGhc4GJd0000

The previous implementation of the Levenshtein distance algorithm + * was from http://www.merriampark.com/ld.htm